将可运行对象提交给执行程序服务后,是否可以修改该对象(具有无限制队列的单线程)?
例如:
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
循环或在其上进行迭代,则需要手动进行同步。