如何從一個線程循環ArrayList
,而從其他線程添加到它?如何從一個線程循環arraylist,而從其他線程添加到它?
1)我有一個線程在ArrayList
上循環並執行一些檢查。
2)我有第二個線程,增加到ArrayList
的結尾。
我有信號燈其暫停第一線第二運行時, 但如何實現這一點:
當第二個線程增加了一些對ArrayList
,第一個線程將繼續從點環路它暫停的地方沒有拋出java.util.ConcurrentModificationException
?
如何從一個線程循環ArrayList
,而從其他線程添加到它?如何從一個線程循環arraylist,而從其他線程添加到它?
1)我有一個線程在ArrayList
上循環並執行一些檢查。
2)我有第二個線程,增加到ArrayList
的結尾。
我有信號燈其暫停第一線第二運行時, 但如何實現這一點:
當第二個線程增加了一些對ArrayList
,第一個線程將繼續從點環路它暫停的地方沒有拋出java.util.ConcurrentModificationException
?
如果你一定要使用ArrayList
你必須同步訪問它。但是,這並不能讓你從ConcurrentModificationExeptions中解脫出來,因爲這並不一定與併發有關。
請注意,此異常不會始終指出對象已經由不同線程併發修改。如果單個線程發出違反對象合約的一系列方法調用,則該對象可能會拋出此異常。例如,如果一個線程在使用快速迭代器迭代集合的同時直接修改集合,迭代器將拋出此異常。
如果您可以確保,只有新項目被附加到列表中,您可以使用索引並手動循環,而不使用迭代器。一旦你到達隊列的盡頭,你就從頭開始。
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
}
假設你不能使用Queue
像ConcurrentLinkedQueue
,這裏是你可以如何進行:
在這裏,我假設你的檢查是快:
主題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
它已經是線程安全的,讀操作非常快,因爲沒有鎖定,但寫操作很慢,因爲它重建整個列表
最簡單的解決方案是使用CopyonWritearrayList它是精確設計這種東西,但注意,它比平常慢ArrayList
請顯示您的代碼 –
你不能。你需要得到一個新的迭代器並重新開始。我建議你自己實現迭代,然後它可能會工作。但只有在「增加陣列列表結束」的情況下。 – Fildor
您應該使用'Vector'而不是'ArayList' – Anarki