簡體   English   中英

Java-在列表上同步getSize()

[英]Java - synchronizing getSize() on List

List<Ball> myObjs = myThreads[threadIndex].getMyObjList();
int initialSize = Collections.synchronizedList(myObjs).size();

引發ConcurrentModificationException。 我也曾嘗試將其放在Synchronized(myObjs)塊中,但它也不起作用。 解決辦法是什么? 我在其他任何使用此列表的地方,它都位於synced(塊)中。

PS此錯誤也最終導致產生BrokenBarrierException。 (是的,我正在使用循環屏障進行同步)

編輯:這是堆棧跟蹤:

Exception in thread "Thread-3" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1091)
at java.util.ArrayList$SubList.size(ArrayList.java:921)
at java.util.Collections$SynchronizedCollection.size(Collections.java:1573)
at Part2.Animation.processCollisions(MyClass.java:133) // This is the call to size()

編輯:循環看起來像

for (int threadIndex=0; threadIndex < numThreads; threadIndex++) {
  List<Ball> myObjs = myThreads[threadIndex].getMyObjList();
  int initialSize = Collections.synchronizedList(myObjs).size();
}

並且無論numThreads如何,當threadIndex = 1時都會發生異常。

查看某些List類的源代碼,我看不到調用size()會引發ConcurrentModificationException可能性。 如果您向我們展示了堆棧跟蹤信息,將會有所幫助。


但是與此同時,您似乎對Collections.synchronizedList功能有基本的誤解。 它的作用是創建並返回一個列表包裝器,以確保對同一包裝器實例的操作進行同步。

無論如何,它不會阻止線程對基礎列表執行不同步的操作。 即您剛剛包裝的列表對象。 如果線程具有基礎列表的引用,則它可以直接訪問它,而無需經過包裝器。 對於相同的基礎列表,使用不同的包裝程序進行同步操作也不起作用。 因此,如果您在同一列表上兩次調用Collections.synchronizedList ,則將創建兩個彼此不同步的不同包裝器。

因此,實際上您的Collections.synchronizedList(myObjs).size()根本不執行任何有意義的同步。 沒有其他線程可以控制所創建的同步列表包裝器,因此沒有其他線程可以通過包裝器與之同步。

它是由subList()引起的,與同步無關。

myObjs是subList()的結果,實際上myObjs是原始List的視圖 如果原始List被修改,則在subList.size()時會發生ConcurrentModificationException 這很有意義,視圖應該與其原始List保持一致。

相反,您可以獲得以下子列表:

List mySubList = new ArrayList(originalList.subList(a, b));

如果要修改具有2個或以上線程的列表,則應使用CopyOnWriteArrayList

“此數組在迭代器的生命周期內永不更改,因此不可能發生干擾,並且保證迭代器不會引發ConcurrentModificationException。”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM