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