2016-07-26 35 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,然後用更新的用戶列表提交一個新任務。否則,您不僅會因爲在線程中篡改列表而面臨可見性問題,而且也無法知道您是否正在修改已在運行的任務。

相關問題