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