[英]Java assignment issues - Is this atomic?
我對Java的分配有一些疑問。
我上課了:
public class Test {
private String s;
public synchronized void setS(String str){
s = s + " - " + str;
}
public String getS(){
return s;
}
}
我在我的setter中使用“synchronized”,並在我的getter中避免它,因為在我的應用程序中,有大量的數據獲取,並且設置很少。 必須同步設置以避免不一致。 我的問題是:獲取和設置變量原子? 我的意思是,在多線程環境中,Thread1即將設置變量s,而Thread2即將獲得“s”。 有沒有辦法讓getter方法能得到與s的舊值或s的新值不同的東西(假設我們只有兩個線程)? 在我的應用程序中獲取新值並不是一個問題,並且獲取舊值不是問題。 但我能得到別的東西嗎?
考慮到這個:
public class Test {
private Map<Integer, String> map = Collections.synchronizedMap(new HashMap<Integer, String>());
public synchronized void setMapElement(Integer key, String value){
map.put(key, value);
}
public String getValue(Integer key){
return map.get(key);
}
}
投入和獲得原子? HashMap如何處理將元素放入其中? 它首先刪除舊值並放入現在的值嗎? 我可以獲得除舊值或新值之外的其他值嗎?
提前致謝!
在第一種情況下, String
恰好對於不安全的發布是安全的(在“新的”Java內存模型(JMM)中),所以這沒關系。
沒有volatile
理論上存在一些沒有最新值的問題,但是最新的含義並不清楚。 您可以使用compare-sand-swap(CAS)循環替換鎖,但是無論鎖是否可能發生爭用,這都可能無法獲得很大的性能提升。
在HashMap
的情況下,如果有另一個線程寫入它,即使是單個編寫器線程,也不安全地讀取未同步的映射。 實際上,已經發現這會導致運行流行軟件的生產系統出現無限循環。 問題中的代碼實際上對地圖使用了兩個鎖,它位於頂部(盡管如果使用迭代器,您需要顯式保持相同的鎖)。 不是final
的確會阻止包含類對於不安全的發布是安全的。 如果map
是volatile
並且你為每個put
創建了一個新的map,那么可以在沒有get的同步的情況下使其安全。
不要將HashMap包裝在某些內容中以使其同步,而是考慮使用java.util.concurrency.ConcurrentHashMap
。
這是HashMap的更新版本,它保證“檢索反映了最近完成的更新操作的結果。”
早期的答案是正確的指向新的(1.5+)JVM,String版本是安全的,關於數據損壞。 你似乎意識到了下行非同步訪問; 不一定通過吸氣劑可見的變化。
但是:更有用的問題是:有理由在這里進行同步嗎? 如果這只是為了有興趣了解這一點,那一切都很好。 但對於實際代碼,讀寫的一般規則是,如果兩者都存在,則兩者都應該同步。 因此,盡管在這種情況下您可以省略同步(可能意味着線程看不到其他線程所做的更改),但這樣做似乎沒什么好處。
也許Read Write Lock可以解決您的問題?
看看它的文檔:
讀寫鎖允許訪問共享數據的並發性高於互斥鎖允許的並發性。 它利用了這樣一個事實:雖然一次只有一個線程(一個編寫器線程)可以修改共享數據,但在許多情況下,任何數量的線程都可以同時讀取數據(因此讀取器線程)。 理論上,使用讀寫鎖所允許的並發性的增加將導致相互使用互斥鎖的性能提高。 ....
在多線程環境中,您需要同步getter以確保客戶端看到s
最新值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.