Groovy中的匿名内部类无法捕获最终的外部变量状态

时间:2018-09-28 17:32:07

标签: multithreading groovy

我正在运行一个测试,其中我使用了代表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并没有真正使迭代器返回的值成为最终值?

0 个答案:

没有答案
相关问题