简体   繁体   English

遍历列表并将可调用对象提交给ExecutorService

[英]Iterating over list and submitting Callables to an ExecutorService

I have a List of users that I want to iterate over and create a Callable for each that is passed to an ExecutorService like so: 我有一个要迭代的用户List ,并为每个传递给ExecutorService的用户创建一个Callable ,如下所示:

ExecutorService executor = Executors.newFixedThreadPool(10);

List<Future<String>> futures = new ArrayList<Future<String>>();

for(final User user : users) {

    Future<String> future = executor.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            return doSomethingWithUser(user);
        }
    });

    futures.add( future );      
}

executor.shutdown();

for(Future<String> future : futures) {
    String message = future.get();
    System.out.println(message);        
}   

I believe this won't work correctly, because the user inside the call() method is not the same current user in the iteration when the Callable was created. 我相信这将无法正常工作,因为在创建Callable时, call()方法内的用户与当前迭代中的用户不同。 In other words: 换一种说法:

for(final User user : users) {

    System.out.println("User: " + user.username); // The current user

    Future<String> future = executor.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            System.out.println("User: " + user.username); // Might not be the same user as above
            return doSomethingWithUser(user);
        }
    });

    futures.add( future );      
}

To fix this, I created a MyCallable class that implements Callable and allows for a constructor 为了解决这个问题,我创建了一个MyCallable类,该类实现Callable并允许构造函数

public abstract class MyCallable<I, O> implements Callable<O> {

    private I param;

    public MyCallable(I param) {
        this.param = param;
    }

    public I getParam() {

        return param;
    }
}

Then in my iterator, I pass the user argument to the constructor 然后在迭代器中,将用户参数传递给构造函数

for(final User user : users) {

    Future<String> future = executor.submit(new MyCallable<User, String>(user) {
        @Override
        public String call() throws Exception {
            return doSomethingWithUser(user);
        }
    });

    futures.add( future );                  
}

This works, but I'm curious if instead of creating a new class called MyCallable I could just use the Callable as an anonymous inner class as I was before. MyCallable ,但是我很好奇是否可以MyCallable以前一样使用Callable作为匿名内部类而不是创建一个名为MyCallable的新类。 However, I would instead add a member variable to it. 但是,我改为向其添加一个成员变量。

for(final User user : users) {

    Future<String> future = executor.submit(new Callable<String>() {
        private User _user = user;
        @Override
        public String call() throws Exception {
            return doSomethingWithUser(_user);
        }
    });

    futures.add( future );      
}

Would this work fine? 这样行得通吗? I've tested it, and it seems to work, but I can be kind of difficult to know with multithreading. 我已经对其进行了测试,并且似乎可以正常工作,但是使用多线程可能很难理解。 Member variables are initialized before the constructor, so in theory my _user variable, should have the correct user, right? 成员变量在构造函数之前初始化,因此理论上我的_user变量应该具有正确的用户,对吗?

Your code will work just fine the way it was originally. 您的代码可以像原来一样正常工作。 Variables used in an anonymous class/lambda are captured when the anonymous class is defined - this is why Java requires them to be effectively final - so you don't need to worry, the value of user will still be the same when the callable runs. 定义匿名类时,将捕获在匿名类/ lambda中使用的变量-这就是Java要求它们有效地为最终变量的原因-因此您不必担心,当可调用对象运行时, user的值仍将相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM