我正在运行一个测试,其中我使用了代表ID的1,000个字符串。我创建了一个具有100个线程的ExecutorService
,循环了1,000个字符串,并为每个字符串创建了Callable
。这在Java中工作正常,但是我在Groovy中发现匿名内部类Callable
没有存储迭代值。
这是我的考试:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class CallableTest {
public static void main( String[] args ) throws InterruptedException, ExecutionException {
CallableTest test = new CallableTest();
test.runTest();
}
public List<String> setupTest(){
List<String> ids = new ArrayList<String>();
for(int i = 0; i < 1000; i++) {
ids.add( "ID_" + i );
}
return ids;
}
public void runTest() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(100);
List<Future<String>> futures = new ArrayList<Future<String>>();
List<String> ids = setupTest();
for(final String id : ids) {
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return doSomethingWithId(id);
}
});
futures.add( future );
}
for(Future<String> future : futures) {
String message = future.get();
System.out.println(message);
}
}
public String doSomethingWithId(String id) {
return "Doing something with ID: " + id;
}
}
Groovy中的问题在这里:
for(final String id : ids) {
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// The ID value here is not the ID value from when the Callable was created
return doSomethingWithId(id);
}
});
futures.add( future );
}
您可以在我的评论中看到,调用方法id
时的doSomethingWithId
值与创建Callable
时的值不同。这导致Doing something with ID: ID_999
大部分时间都被打印。
如果我将其复制到Java项目并运行,它将按预期运行。我从0-999得到Doing something with ID: ID_x
,没有重复。
为什么这在Groovy中不起作用?我的理解是Groovy应该支持匿名内部类,但是似乎匿名内部类Callable
在创建匿名类时没有捕获外部变量id
状态。我正在将Java 7与Groovy 2.3.10结合使用。
更新 我发现添加以下内容可以完成这项工作:
for(final String id : ids) {
final String myId = id // This makes it work
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return doSomethingWithId(myId);
}
});
futures.add( future );
}
好像Groovy并没有真正使迭代器返回的值成为最终值?