1

我试图在循环内编写一个开关,在 2/5 的情况下,创建了一个匿名类,它捕获循环计数器。这不是直截了当的,因为计数器需要是最终的才能被匿名内部类捕获。解决方案很简单,只需将 afinal int i_设置为 counter 变量即可。问题是它不起作用(我猜是因为不止一种情况)。这是一段极其简化的代码,与我的真实代码存在相同的问题:

import java.util.concurrent.*;
import java.util.*;
enum E {A,B,C,D,E}
class A {
    static void s() {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    static Semaphore s = new Semaphore(2); // 2 cores
    public static void main(String[] _){
        LinkedList<E> es = new LinkedList<E>();
        es.push(E.A);
        es.push(E.D);
        es.push(E.B);
        es.push(E.C);
        es.push(E.E);
        es.push(E.C);
        es.push(E.C);
        es.push(E.E);
        es.push(E.A);
        es.push(E.A);
        f(es);
    }
    static void f(List<E> es) {
        int i = 0;
        for (E e : es) {
            s.acquireUninterruptibly();
            switch(e) {
            case A:
                final int i_ = i;
                new Thread() {
                    public void run() {
                        System.out.println("A" + i_); s(); s.release();
                    }
                }.start();
                break;
            case B:
                final int i_ = i;
                new Thread() {
                    public void run() {
                        System.out.println("B" + i_); s(); s.release();
                    }
                }.start();
                break;
            case C:
                new Thread() {
                    public void run() {
                        System.out.println("C"); s(); s.release();
                    }
                }.start();
                break;
            case D:
                new Thread() {
                    public void run() {
                        System.out.println("D"); s(); s.release();
                    }
                }.start();
                break;
            case E:
                new Thread() {
                    public void run() {
                        System.out.println("E"); s(); s.release();
                    }
                }.start();
                break;
            default:
                break;
            }
            i++;
        }
    }
}

它产生线程来完成工作。做什么工作由输入列表中的当前元素决定es。信号量用于限制当前运行的线程数。

它无法编译,声称i已经定义:

$ javac A.java && java A
A.java:27: i_ is already defined in main(java.lang.String[])
                final int i_ = i;
                          ^
1 error

但是它们在交换机的不同情况下被定义。我认为它会起作用,因为您可以对任何其他类型的块做同样的事情,例如这有效:

class A {
    static {
        for (int i = 0; i < 1; i++) {
            int j = i + 1;
        }
        for (int i = 0; i < 1; i++) {
            int j = i + 1;
        }
    }
}

为什么它不能与开关一起使用?还有哪些其他方法可以在多个案例中的匿名类中围绕开关捕获计数器?

4

2 回答 2

3

添加大括号:

case A: {
    ...
}
case B: {
    ...
}
...

正如您所拥有的,所有i_声明都在同一范围内,这会导致编译错误。在大括号内嵌套在同一级别的两段代码{}始终处于同一范围内,因此声明位于不同 s 中的事实case没有区别。

于 2013-09-16T22:50:07.633 回答
1

只需将索引与列表一起压缩即可。自几十年前在 ML 等人中,这一直是一个常见的习语。我认为这种方法比 arshajii 的方法更干净,因为它也消除了流浪i++。此外,大多数 Java 用户不熟悉 case 周围的普通块(同样,他们可能会同样惊讶地看到zip)。如果您使用包含zip. 或者它应该在标准库中。我在您的班级底部附加了一个实现。

import java.util.concurrent.*;
import java.util.*;
enum E {A,B,C,D,E}
class A {
    static void s() {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    static Semaphore s = new Semaphore(2); // 2 cores
    public static void main(String[] _){
        LinkedList<E> es = new LinkedList<E>();
        es.push(E.A);
        es.push(E.D);
        es.push(E.B);
        es.push(E.C);
        es.push(E.E);
        es.push(E.C);
        es.push(E.C);
        es.push(E.E);
        es.push(E.A);
        es.push(E.A);
        f(es);
    }
    static void f(List<E> es) {
        for (final Pair<Integer,E> p : zip(naturals, es)) {
            s.acquireUninterruptibly();
            switch(p.y) {
            case A:
                new Thread() {
                    public void run() {
                        System.out.println("A" + p.x); s(); s.release();
                    }
                }.start();
                break;
            case B:
                new Thread() {
                    public void run() {
                        System.out.println("B" + p.x); s(); s.release();
                    }
                }.start();
                break;
            case C:
                new Thread() {
                    public void run() {
                        System.out.println("C"); s(); s.release();
                    }
                }.start();
                break;
            case D:
                new Thread() {
                    public void run() {
                        System.out.println("D"); s(); s.release();
                    }
                }.start();
                break;
            case E:
                new Thread() {
                    public void run() {
                        System.out.println("E"); s(); s.release();
                    }
                }.start();
                break;
            default:
                break;
            }
        }
    }

    // an infinite iterable over all natural numbers
    static Iterable<Integer> naturals = new Iterable<Integer>() {
        public Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
                private int i = 0;
                public void remove() {
                    throw new UnsupportedOperationException();
                }
                public Integer next() {
                    return i++;
                }
                public boolean hasNext() {
                    return true;
                }
            };
        }
    };

    // combine two iterators
    static <X,Y> Iterable<Pair<X,Y>> zip(final Iterable<X> i1,
                                         final Iterable<Y> i2) {
        return new Iterable<Pair<X,Y>>() {
            public Iterator<Pair<X,Y>> iterator() {
                return new Iterator<Pair<X,Y>>() {
                    private final Iterator<X> ix = i1.iterator();
                    private final Iterator<Y> iy = i2.iterator();
                    public void remove() {
                        ix.remove();
                        iy.remove();
                    }
                    public Pair<X,Y> next() {
                        Pair<X,Y> p = new Pair<X,Y>();
                        p.x = ix.next();
                        p.y = iy.next();
                        return p;
                    }
                    public boolean hasNext() {
                        return ix.hasNext() && iy.hasNext();
                    }
                };
            }
        };
    }
}

class Pair<X,Y> {
    X x;
    Y y;
}

javac A.java && java A
A0
A1
E
C
C
E
C
B7
D
A9
于 2013-09-17T20:43:34.753 回答