摘要:無狀態(tài)的是線程安全的,當無狀態(tài)變?yōu)橛袪顟B(tài)時就是不安全的破壞了線程的安全性,非原子性操作競態(tài)條件在并發(fā)編程中,由于不恰當的執(zhí)行時序而出現的不正確結果是一種非常重要的情況,被稱之為競態(tài)條件。重入意味著獲取鎖的操作的粒度是線程,而不是調用。
這本書的內容是什么?
本書提供了各種實用的設計規(guī)則,用于幫助開發(fā)人員創(chuàng)建安全的和高性能的并發(fā)類。什么類是線程安全的?
當多個線程訪問某個類時,這個類始終都能表現出正確的行為,那么就稱這個類是線程安全的。無狀態(tài)的sevlet是線程安全的, 當無狀態(tài)變?yōu)橛袪顟B(tài)時就是不安全的
@NotThreadSafe public class UnsafeCountingFactorizer extends GenericServlet implements Servlet { private long count = 0; public long getCount() { return count; } public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = factor(i); ++count;//破壞了線程的安全性 ,非原子性操作 encodeIntoResponse(resp, factors); } void encodeIntoResponse(ServletResponse res, BigInteger[] factors) { } BigInteger extractFromRequest(ServletRequest req) { return new BigInteger("7"); } BigInteger[] factor(BigInteger i) { // Doesn"t really factor return new BigInteger[] { i }; } }競態(tài)條件(Race Condition)
在并發(fā)編程中,由于不恰當的執(zhí)行時序而出現的不正確結果是一種非常重要的情況,被稱之為競態(tài)條件。 1)當某個計算結果的正確性取決于多線程的交替執(zhí)行時序是,那么就會出現競態(tài)條件。換句話說,那就是正確的結果取決于運氣。 2)競態(tài)條件的本質——基于可能失效的觀察結果來做出判斷或者執(zhí)行某個計算。 這類競態(tài)條件被稱之為“先檢查后執(zhí)行”。 下面是一種常見情況,延遲初始化。 @NotThreadSafe public class LazyInitRace { private ExpensiveObject instance = null; public ExpensiveObject getInstance() { if (instance == null) instance = new ExpensiveObject(); return instance; } } class ExpensiveObject { }復合操作
UnsafeCountingFactorizer 和 LazyInitRace 都包含一組需要以原子方式執(zhí)行(或者說不可分割)的操作。加鎖機制
類似AtomicLong的AtomicRreference來管理因數分解的數值及分解結果? // 這個方法不正確,盡管這些原子引用本身都是現成安全的,但是組合在一起就不是線程安全的了。 //存在lastNumber和lastFactors沒有同時更新的情況 @NotThreadSafe public class UnsafeCachingFactorizer extends GenericServlet implements Servlet { private final AtomicReference內置鎖lastNumber = new AtomicReference (); private final AtomicReference lastFactors = new AtomicReference (); public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber.get())) encodeIntoResponse(resp, lastFactors.get()); else { BigInteger[] factors = factor(i); lastNumber.set(i); lastFactors.set(factors); encodeIntoResponse(resp, factors); } } void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) { } BigInteger extractFromRequest(ServletRequest req) { return new BigInteger("7"); } BigInteger[] factor(BigInteger i) { // Doesn"t really factor return new BigInteger[]{i}; } } 要保持狀態(tài)一致性,就需要在單個原子操作中更新所有先關的狀態(tài)變量。
每個java對象都可以用做一個實現同步的鎖,這些鎖被稱之為內置鎖(Intrinsic lock)或監(jiān)視器鎖(Monitor Lock)。線程在進入同步代碼塊(Synchronized Block)之前會自動獲得鎖,并且在退出同步代碼塊時自動釋放鎖,而無論是通過正產的控制路徑退出,還是通過從代碼塊中拋出異常退出。 獲得鎖的位移方法就是進入由這個鎖保護的同步代碼快或者方法。
@ThreadSafe public class SynchronizedFactorizer extends GenericServlet implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; //同步方法 //并發(fā)性能太差,不推薦這么做 public synchronized void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber)) encodeIntoResponse(resp, lastFactors); else { BigInteger[] factors = factor(i); lastNumber = i; lastFactors = factors; encodeIntoResponse(resp, factors); } } void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) { } BigInteger extractFromRequest(ServletRequest req) { return new BigInteger("7"); } BigInteger[] factor(BigInteger i) { // Doesn"t really factor return new BigInteger[] { i }; } }重入
如果某個線程試圖獲得一個已經由他自己持有的鎖,那么這個請求就會成功。
“重入”意味著獲取鎖的操作的粒度是“線程”,而不是“調用”。
注意兩點:
1 通常,在簡單性與性能之間存在著某種互相制約因素。當實現某個同步策略時,一定不要盲目地為了性能而犧牲簡單性。 2 當執(zhí)行時間較長的計算或者可能無法快速完成的操作時(例如,網絡I/O操作或者控制臺I/O),一定不要持有鎖。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74387.html
摘要:線程封閉當訪問共享的可變數據時,通常需要使用同步。如果僅在單線程內訪問數據,就不要同步。這種技術成為線程封閉。棧封閉棧封閉是線程封閉的一種特例,在棧封閉中,只能通過局部變量才能訪問對象。,對象是正確創(chuàng)建的。 線程封閉 當訪問共享的可變數據時,通常需要使用同步。一種避免使用同步的方式就是不共享數據。如果僅在單線程內訪問數據,就不要同步。這種技術成為線程封閉(Thread Confine...
摘要:對象的組合介紹一些組合模式,這些模式能夠使一個類更容易成為線程安全的,并且維護這些類時不會無意破壞類的安全性保證。狀態(tài)變量的所有者將決定采用何種加鎖協議來維持變量狀態(tài)的完整性。所有權意味著控制權。 對象的組合 介紹一些組合模式,這些模式能夠使一個類更容易成為線程安全的,并且維護這些類時不會無意破壞類的安全性保證。 設計線程安全的類 在設計線程安全類的過程中,需要包含以下三個基本要素: ...
摘要:對象的共享上一章介紹了如何通過同步來避免多個線程在同一時刻訪問相同的數據,而本章將介紹如何共享和發(fā)布對象,從而使它們能夠安全地由多個線程同時訪問。為了確保多個線程的之間對內存寫入操作的可見性,必須使用同步機制。 對象的共享 上一章介紹了如何通過同步來避免多個線程在同一時刻訪問相同的數據,而本章將介紹如何共享和發(fā)布對象,從而使它們能夠安全地由多個線程同時訪問。 列同步代碼塊和同步方法可...
摘要:上集算法實現的優(yōu)點當一個線程執(zhí)行任務失敗不影響其他線程的進行最大限度的利用資源能提高程序的伸縮性伸縮性不修改任何代碼升級硬件就能帶來性能上的提高升級硬件帶來的性能提高明顯就是伸縮性良好的缺點代碼復雜影響閱讀性剛開始看的時候沒有正確的思路理解 ConcurrentLinkedQueue(上集) 算法實現 CAS CAS的優(yōu)點 當一個線程執(zhí)行任務失敗不影響其他線程的進行 最大限度的利用...
Python作為一門常見的編程語言,可以用到的地方是比較的多的,而且他還能夠去編程相關的游戲,那么,下文就會給大家教一個比較簡單的小游戲,就是寫猜數字和字母的游戲,詳細的內容可以看下文,看完之后,可以自己去手動敲下代碼哦。 前言 學完語法和正在學習語法的時候,我們可以在空閑的時候,寫幾個簡單的小項目,今天我們就用最基礎的語法看兩個實戰(zhàn)語法練習 猜數字游戲 項目游戲說明:讓用戶輸入一個數...
閱讀 2137·2023-04-25 18:49
閱讀 1840·2019-08-30 14:02
閱讀 2643·2019-08-29 17:24
閱讀 3323·2019-08-28 18:10
閱讀 2926·2019-08-28 18:03
閱讀 488·2019-08-26 12:01
閱讀 3309·2019-08-26 11:31
閱讀 1409·2019-08-26 10:29