2016-05-09 45 views
0

如何從一個線程循環ArrayList,而從其他線程添加到它?如何從一個線程循環arraylist,而從其他線程添加到它?

1)我有一個線程在ArrayList上循環並執行一些檢查。

2)我有第二個線程,增加到ArrayList的結尾。

我有信號燈其暫停第一線第二運行時, 但如何實現這一點:

當第二個線程增加了一些對ArrayList,第一個線程將繼續從點環路它暫停的地方沒有拋出java.util.ConcurrentModificationException

+1

請顯示您的代碼 –

+0

你不能。你需要得到一個新的迭代器並重新開始。我建議你自己實現迭代,然後它可能會工作。但只有在「增加陣列列表結束」的情況下。 – Fildor

+0

您應該使用'Vector'而不是'ArayList' – Anarki

回答

6

如果你一定要使用ArrayList必須同步訪問它。但是,這並不能讓你從ConcurrentModificationExeptions中解脫出來,因​​爲這並不一定與併發有關。

JavaDoc

請注意,此異常不會始終指出對象已經由不同線程併發修改。如果單個線程發出違反對象合約的一系列方法調用,則該對象可能會拋出此異常。例如,如果一個線程在使用快速迭代器迭代集合的同時直接修改集合,迭代器將拋出此異常。

如果您可以確保,只有新項目被附加到列表中,您可以使用索引並手動循環,而不使用迭代器。一旦你到達隊列的盡頭,你就從頭開始。

ArrayList q = new ArrayList<>(); 

//thread 1  
Object o = ...; 
synchronized(q) { 
    q.add(o); //append 
} 

//thread 2 
int i = 0; 
synchronized(q) { 
    int size = q.size(); 
    for(; i < size; i++){ 
    Object o = q.get(i); 
    //do something with o 
    } 
    if(i >= size) { 
    i = 0; 
    } 
} 

但這樣做這樣會導致你有點順序的行爲,無論是一個或另一個線程可以在列表上一次操作。唯一的「優點」是線程模型爲循環操作增加了一些隨機性。所以,你可以以及跳過同步和併發性,只是做

q.add(o); //append 
//you may add a random condition, i.e. time interval, item count random number to trigger the loop process so it don't get exectued on each add 
for(Object o : q){ 
    //do something with o 
} 

當然你也可以使用一個安全,複製爲尼古拉斯寫道,但是這是容器結構(表)的只是一個淺拷貝,而不是它的內容。所以,如果你這樣做,確保項目是線程安全的或不要修改它們。

如果第二個線程偶爾從列表末尾移除一個項目,最好使用一個隊列。 Java爲此提供了Deque。一個線程可以在一端添加元素,而另一個線程則可以從另一個線程移除。當你在多線程使用它,然後手動同步很爛,你最好使用一個線程安全的實現,並跳過同步:

Deque q = new ConcurrentLinkedDeque<>(); 

//thread 1  
Object o = ...; 
q.addFirst(o); 

//thread 2 
while(!q.isEmpty()){ 
    Object o = q.removeLast(); 
    //do something with o 
} 
1

假設你不能使用QueueConcurrentLinkedQueue,這裏是你可以如何進行:

在這裏,我假設你的檢查是快:

主題1:

synchronized(list) { 
    for (MyClass obj : list) { 
     // check what you want here 
    } 
} 

線程2:

synchronized(list) { 
    list.add(obj); 
} 

在這裏,我假設你的檢查是緩慢:

主題1:

List<MyClass> safeCopy; 
synchronized(list) { 
    safeCopy = new ArrayList<>(list); 
} 
for (MyClass obj : safeCopy) { 
    // check what you want here 
} 

線程2:

同上

如果你d不要太頻繁地修改你的列表你應該使用CopyOnWriteArrayList它已經是線程安全的,讀操作非常快,因爲沒有鎖定,但寫操作很慢,因爲它重建整個列表

0

最簡單的解決方案是使用CopyonWritearrayList它是精確設計這種東西,但注意,它比平常慢ArrayList