2017-03-19 59 views
-1

衆所周知,如果另一個線程碰巧併發地修改了集合,那麼在集合上迭代而沒有同步的風險會引發ConcurrentModificationException可以Collection.size()拋出ConcurrentModificationException?

但是如何在集合上調用size()size()是否涉及迭代來計算集合中元素的數量?如果是這種情況,ConcurrentModificationException可能會發生(有些人報告這一點,例如here,但對我來說,不清楚尺寸()是罪魁禍首)。

另一方面,如果size()只是得到一個內部int計數器變量,不會發生異常。

哪一個是這種情況?

HUMBLE編輯:感謝answerers的精度,這取決於實施。我應該提到它是一個TreeMap。我可以在那張地圖上遇到這個問題嗎?文檔沒有提及TreeMap.size()。

+1

線程安全不是關於是否會拋出ConcurrentModificationException。如果所有線程安全錯誤都如此明顯可見,人們會*愛*。 – user2357112

+1

完全取決於收藏。 – SLaks

+1

它取決於Collection接口的實現。 – vhula

回答

1

文檔don't explicitly state如果您調用Collection#size,將發生ConcurrentModificationException

唯一真正倍它拋出are described in ConcurrentModificationException itself

此異常可能由已檢測出的對象的併發修改時這種修改是不允許的方法被拋出。

例如,一個線程在另一個線程遍歷它時修改一個集合通常是不允許的。一般來說,在這些情況下迭代的結果是不確定的。某些迭代器實現(包括由JRE提供的所有通用集合實現的實現)可能會選擇在檢測到此行爲時拋出此異常。這樣做的迭代器被稱爲快速迭代器,因爲它們快速且乾淨地失敗,而在將來未定的時間冒着任意的,非確定性的行爲冒險。

如果你真的擔心這樣的事情,那麼請確保您的收藏的具體實現是使用approriate size()方法,像ConcurrentLinkedQueue

返回此隊列中元素的數量。如果此隊列包含多個Integer.MAX_VALUE元素,則返回Integer.MAX_VALUE。 請注意,與大多數集合不同,此方法不是一個常量操作。由於這些隊列的異步特性,確定當前元素數量需要進行O(n)遍歷。

此外,如果在執行此方法期間添加或刪除元素,則返回的結果可能不準確。因此,這種方法在併發應用程序中通常不是很有用。

+0

這是一個TreeMap。 – ARX

+0

@ARX:我鼓勵你看一下具體實現'ConcurrentMap'的文檔,然後。 – Makoto

1

size()是否會丟失ConcurrentModificationException並不重要。幾乎沒有收藏會在size()上拋出異常,但這並不安全。

當您在其他線程修改的集合上調用size()時,您正在讀取共享內存。如果您使用的集合沒有提供特定的同步保證,並且您沒有使用其他同步機制,那麼您讀取的值可能是任意過時的,或者甚至可能與您認爲「hasn還沒有發生「。

相關問題