Я запускаю тест, в котором беру 1000 строк, которые представляют собой идентификатор.Я создаю ExecutorService
с 100 потоками, зацикливаю 1000 строк и создаю 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-проект и запустите его, он будет работать, как и ожидалось.Я получаю Doing something with ID: ID_x
от 0-999 без дубликатов.
Почему это не работает в 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 нена самом деле сделать значение, возвращаемое из итератора final?