将可运行对象提交给执行程序服务后,是否可以修改该对象(具有无限制队列的单线程)?

例如:

public class Test {
    @Autowired
    private Runner userRunner;

    @Autowired
    private ExecutorService executorService;

    public void init() {
        for (int i = 0; i < 100; ++i) {
             userRunner.add("Temp" + i);
             Future runnerFuture = executorService.submit(userRunner);
        }
    }
}

public class Runner implements Runnable {
    private List<String> users = new ArrayList<>();

    public void add(String user) {
        users.add(user);
    }

    public void run() {
       /* Something here to do with users*/
    }
}


如上例所示,如果我们在循环内提​​交可运行对象并修改了对象的内容,则第一次提交给执行者服务将使用新添加的用户。考虑到run方法正在做一些真正的密集工作,并且随后的提交被排队。

最佳答案

如果我们在循环内提​​交可运行对象并修改了对象的内容,则第一次提交给执行者服务将使用新添加的用户。


仅当users ArrayList正确同步时。您正在做的是尝试从两个不同的线程修改users字段,这可能导致异常和其他不可预测的结果。同步可确保互斥锁,以便多个线程不会意外地同时更改ArrayList,而内存同步可确保一个线程的修改被另一线程看到。

您可以做的是将同步添加到示例中:

public void add(String user) {
    synchronized (users) {
        users.add(user);
    }
}
...

public void run() {
   synchronized (users) {
       /* Something here to do with users*/
   }
}


另一个选择是同步列表:

// you can't use this if you are iterating on this list (for, etc.)
private List<String> users = Collections.synchronizedList(new ArrayList<>());


但是,如果要在列表上使用for循环或在其上进行迭代,则需要手动进行同步。

10-07 19:40
查看更多