2016-07-26 38 views
0

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

例如:

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*/ 
    } 
} 

正如你可以在上面的例子中看到,如果我们提交一个Runnable对象并修改对象的内容过于循环内,将第一次提交给执行程序服务使用新增用户。考虑一下,run方法正在做一些非常密集的事情,随后的提交会排队。

回答

1

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

只有在usersArrayList正确同步。你正在做的是试图修改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循环或以其他方式迭代它。

0

最干净,最直接的方法是在Future上调用cancel,然后用更新的用户列表提交一个新任务。否则,您不仅会因为在线程中篡改列表而面临可见性问题,而且也无法知道您是否正在修改已在运行的任务。

相关问题