[英]Java Concurrency in Practice: 3.5.4 Effectively immutable objects: Do we need Thread-Safe Collection containers for effectively immutable objects
3.5.4節討論了有效的不可變對象,即,一旦對象被安全且完整地構造,其狀態將不會被任何代碼路徑的任何代碼更改。
格茨爵士舉了一個例子:
例如,
Date
是可變的,但是如果您將其當作不可變的來使用,則可以消除跨線程共享[共享]日期時所需的鎖定。 假設您要維護一個存儲每個用戶的最后登錄時間的映射:public Map<String, Date> lastLogin = Collections.synchronizedMap(new HashMap<String, Date>());
如果將
Date
值放置在Map
后未對其進行修改,則synchronizedMap
實現中的synchronizedMap
足以安全地發布Date
值,並且在訪問它們時不需要其他同步。
我是無法理解的一點是,為什么我們要使用synchronizedMap
並承擔其內部lockings的額外開銷時,我們可以簡單地使用不安全的Map
,因為畢竟我們就會將有效不變Date
對象了-這意味着,一旦正確,完整地構建和發布,它就不會再發生變異。 因此,即使Map
本身是不安全的,在其他線程已從Unsafe Map
檢索到它的Date
實例中的任何代碼路徑中,也不會存在任何代碼可以同時變異任何Date
實例。
綜上所述,有效不可變對象的前提並不需要任何線程安全的容器,因為我們不應該在任何代碼路徑中為有效不可變對象提供任何可變代碼。
如果您使用un-synchronized
mutable map
並在threads
之間共享它,那么將有兩個thread-safety
問題: visibility
和atomicity
。 Thread-1
不會知道Thread-2
是否已刪除Map-Entry
還是將其值替換為新的Date
對象。
// not atmoic and doesn't guarantee visiblity
if(map.contains(key)){
map.put(key,newDate);
}
原始文本中的主題詞是“完全構建並發布”。 “發布”尤其是指使一個線程創建的對象對其他線程可見,並且當該對象不是真正不變的時,則必須安全地完成該對象(Google“ Java安全發布”)。
如果沒有同步,Java不能保證一個線程所做的變量更新將被其他線程看到,或者不能以什么順序看到更新。
在大多數計算機體系結構中,為所有線程提供一致的共享內存視圖是相對昂貴的。 通過不要求線程具有除顯式同步之外的一致視圖,Java允許線程在需要時獲得一致的視圖,或在不需要時獲得最佳性能。
同樣,以上所有內容都忽略了程序出於其他原因(例如,防止同時進行的更新破壞Map本身)而需要同步對Map的訪問的可能性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.