2013-01-24 180 views
9

我有一個方法(下面的例子)創建一個新的列表,將一些東西放入它,並將它傳遞給另一個線程進行操作。將本地新對象傳遞給線程,線程安全嗎?

這似乎是線程安全的。該列表是本地的創建它的方法。該方法在列表上運行,並且不會將它傳遞給另一個線程,直到完成對它的操作爲止。

但這感覺錯誤,因爲該列表是在兩個單獨的線程中訪問,但它不同步。

這是可以接受的線程安全代碼嗎?

class App 
{ 
    public static void main(String[] args) 
    { 
    final ArrayList<Integer> list = new ArrayList<Integer>(); 
    list.add(4); 
    list.add(5); 

    final ExecutorService es = Executors.newSingleThreadExecutor(); 
    es.execute(new Runnable() { 
     @Override public void run() 
     { 
      for (Integer i : list) 
      System.out.println(i); 
     }}); 
    es.shutdown(); 
    } 
} 

回答

10

它是安全的,因爲一個線程寫入到列表中,然後一個其他線程從列表中讀取,而當你提交一個任務執行者的服務保證了發生-之前的關係。從the documentation

引用:

的java.util.concurrent中和所有類的方法及其子包 這些保證擴展到更高級別的同步。在 特別是:

[...]

提交一個Runnable之前操作的線程的執行器發生-before其執行開始。同樣將Callables 提交給ExecutorService。

1

這是線程安全的,是因爲這是main創建線程,因爲它正在建設其啓動底層的線程,並因爲它通過它同步的BlockingQueue執行人。

你需要小心的是什麼:

  1. 傳遞一個列表開了個線程對象的構造函數內,因爲JIT能夠優化字段初始化構造。

  2. 將列表傳遞給另一個線程沒有同步。例如,如果一個線程初始化列表,然後將其設置在可從另一個線程訪問的本地字段上。