我试图在循环中编写一个开关,其中2/5的情况下,创建了一个匿名类,它捕获循环计数器。这不是直截了当的,因为计数器需要是最终的才能被匿名内部类捕获。解决方案很简单,只需将final int i_
设置为计数器变量即可。问题是它不起作用(我想因为有不止一个案例)。这是一段极其简化的代码,与我的实际代码中的问题相同:
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;
}
}
}
为什么它不适用于交换机?在多个案例中,有哪些其他方法可以在匿名类中围绕交换机捕获一个计数器?
答案 0 :(得分:3)
添加大括号:
case A: {
...
}
case B: {
...
}
...
如上所述,所有i_
声明都在同一范围内,这会导致编译错误。在{}
括号内嵌套在同一级别的两段代码总是在同一范围内,因此声明在不同case
s中的事实没有区别。
答案 1 :(得分:1)
只需用列表压缩索引即可。这是几十年前ML等人的一个常见习语。我认为这种方法比arshajii更清洁,因为它也消除了迷路i++
。此外,大多数Java用户不熟悉案例周围的普通块(然后再次看到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