2014-02-11 71 views
1

我有幾個ArrayList<T>包含用戶定義的對象(例如List<Student>, List<Teachers>)。對象本質上是不可改變的,即不提供setter,而且由於問題的本質,「沒有人」會試圖修改這些對象。一旦'ArrayList'被填充,不允許進一步添加/移除對象/可能。所以List不會動態改變。ArrayList可用於多線程環境中的只讀目的嗎?

在這樣的給定條件下,這個數據結構(即ArraList)能否被多線程(同時)安全地使用?每個線程將只讀取對象屬性,但沒有可能的「設置」操作。

所以,我的問題是我可以依靠ArrayList?否則,在這種情況下可以使用哪些其他更便宜的數據結構?

+2

如果對象不可能有來自不同線程的狀態變化,那麼問題是什麼?也許我讀錯了這個問題,但它似乎是一個明智之舉。唯一的問題可能是如果任何ArrayList元素的狀態可以改變。我不會將列表傳遞給其他對象,而是將列表的深層副本或類的對象完全封裝並保護列表。 –

+0

是的,你可以。嘗試一下。 –

+2

您可能仍然需要某種同步來確保初始化列表的寫操作發生在讀操作之前,其中*發生之前*指的是[JLS中定義的概念](http://docs.oracle.com)。 com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5),否則可能會遇到緩存一致性或指令重新排序的問題,導致其他線程看到部分構建的列表。 – user2357112

回答

1

是的,你應該能夠將數組傳遞給每個線程。只要在任何線程可能獲取信息之前數組完成寫入,應該沒有訪問錯誤。

2

如果線程在安全出版物之後從未修改過,則可以共享線程之間的任何對象或數據結構。如註釋中所述,在初始化ArrayList的寫入和其他線程獲取引用的讀取之間必須存在* happen-before *關係。

E.g.如果在啓動其他線程之前或在將列表中的任務提交到ExecutorService之前完全設置了ArrayList,則表明您是安全的。

如果線程已經運行,則必須使用其中一個線程安全機制將ArrayList引用移交給其他線程,例如,通過把它放在BlockingQueue

即使是最簡單的形式,如將參考文件存儲到static finalvolatile字段也可以使用。

請記住,以後不要修改對象的前提條件必須始終成立。我們建議使用Collections.unmodifiableList(…)包裝清單執行這一約束,忘了原來的列表引用發佈前:

class Example { 
    public static final List<String> THREAD_SAFE_LIST; 
    static { 
    ArrayList<String> list=new ArrayList<>(); 
    // do the setup 
    THREAD_SAFE_LIST=Collections.unmodifiableList(list); 
    } 
} 

class Example { 
    public static final List<String> THREAD_SAFE_LIST 
    =Collections.unmodifiableList(Arrays.asList("foo", "bar")); 
}