Java并發(fā)編程之線程安全性
1.什么是線程安全性
當(dāng)多個(gè)線程訪問(wèn)某個(gè)類(lèi)時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)用方式或者這些線程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)同,這個(gè)類(lèi)都能表現(xiàn)出正確的行為,那么就稱這個(gè)類(lèi)是線程安全的。
無(wú)狀態(tài)的對(duì)象一定是線程安全的,比如:Servlet
。
2.原子性
2.1 競(jìng)爭(zhēng)條件
由于不恰當(dāng)?shù)膱?zhí)行時(shí)序而出現(xiàn)不正確的結(jié)果的情況,就是競(jìng)爭(zhēng)條件。
“先檢查后執(zhí)行”操作,即通過(guò)一個(gè)可能實(shí)效的觀測(cè)結(jié)果來(lái)決定下一步的動(dòng)作。比如:延遲初始化。
if(instance == null) { instance = new SomeObject(); }
“讀取-修改-寫(xiě)入”的操作,其結(jié)果狀態(tài)依賴于之前的狀態(tài)。如:遞增運(yùn)算。
long count = 0; count++;
2.2 復(fù)合操作
原子操作是指,對(duì)于訪問(wèn)同一個(gè)狀態(tài)的所有操作(包括此操作本身)來(lái)說(shuō),這個(gè)操作是以一個(gè)原子方式執(zhí)行(不可分割)的操作。
為了確保線程安全性,包含了一組必須以原子方式執(zhí)行的操作,稱為復(fù)合操作。
遞增運(yùn)算可以使用一個(gè)現(xiàn)有的線程安全類(lèi),確保線程安全性。如:
AtomicLong count = new AtomicLong(0); count.incrementAndGet();
3.加鎖機(jī)制
當(dāng)類(lèi)只有一個(gè)狀態(tài)變量時(shí),可以通過(guò)線程安全的狀態(tài)變量來(lái)維護(hù)類(lèi)的線程安全性。但如果類(lèi)有更多的狀態(tài)時(shí),就不能只添加更多線程安全的狀態(tài)變量了。要保持狀態(tài)的一致性,就需要在單個(gè)原子操作中更新所以相關(guān)的狀態(tài)變量。
3.1 內(nèi)置鎖
Java提供一種內(nèi)置鎖:同步代碼塊,它包括:一個(gè)作為鎖的對(duì)象引用、一個(gè)作為由這個(gè)鎖保護(hù)的代碼塊。
以關(guān)鍵字synchronized
來(lái)修飾的方法就是一種橫跨整個(gè)方法體的同步代碼塊,其中該同步代碼塊的鎖就是方法調(diào)用所在的對(duì)象。靜態(tài)的synchronized
方法以Class對(duì)象作為鎖。
線程在進(jìn)入同步代碼塊之前會(huì)自動(dòng)獲得鎖,在退出同步代碼塊是自動(dòng)釋放鎖。最多只有一個(gè)線程能持有這種鎖,因此同步代碼會(huì)以原子方式執(zhí)行。
3.2 重入
內(nèi)置鎖是可重入的,意味著獲取鎖的操作的粒度是線程,不是調(diào)用。當(dāng)某個(gè)線程試圖獲得一個(gè)已經(jīng)由它自己持有的鎖時(shí),這個(gè)請(qǐng)求也會(huì)成功。
重入進(jìn)一步提升了加鎖行為的封裝性,簡(jiǎn)化了面向?qū)ο蟛l(fā)代碼的開(kāi)發(fā)。
public class Widget { public synchronized void doSomething() { //...... } } public class LoggingWidget extends Widget { public synchronized void doSomething() { //...... super.doSomething();//假如沒(méi)有可重入的鎖,該語(yǔ)句將產(chǎn)生死鎖。 } }
4.用鎖保護(hù)狀態(tài)
對(duì)于可能被多個(gè)線程同時(shí)訪問(wèn)的可變狀態(tài)變量,在訪問(wèn)它時(shí)都需要持有同一個(gè)鎖,在這種情況下,稱狀態(tài)變量是由這個(gè)鎖保護(hù)的。
5.活躍性與性能
粗粒度地使用鎖,雖然確保了線程安全性,但可能造成性能問(wèn)題和活躍度問(wèn)題,如:
@ThreadSafe public class SynchronizedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public synchronized void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber)) encodeIntoResponse(resp, lastFactors); else { BigInteger[] factors = factor(i);//因數(shù)分解計(jì)算 lastNumber = i; lastFactors = factors;//存放上一次計(jì)算結(jié)果 encodeIntoResponse(resp, factors); } } }
可以通過(guò)縮小同步代碼塊,既確保servlet的并發(fā)型,又維護(hù)線程安全性。不要把本應(yīng)是原子操作拆分到多個(gè)同步代碼塊中,盡量將不影響共享狀態(tài)且執(zhí)行時(shí)間較長(zhǎng)的操作從同步代碼中分離出來(lái)。如:
public class CachedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = null; synchronized (this) { if (i.equals(lastNumber)) { factors = lastFactors.clone(); } } if (factors == null) { factors = factor(i); synchronized (this) { lastNumber = i; lastFactors = factors.clone(); } } encodeIntoResponse(resp, factors); } }
到此這篇關(guān)于Java并發(fā)編程之線程安全性的文章就介紹到這了,更多相關(guān)Java 線程安全性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot錯(cuò)誤處理機(jī)制實(shí)現(xiàn)原理解析
這篇文章主要介紹了springboot錯(cuò)誤處理機(jī)制實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Mybatis實(shí)現(xiàn)分頁(yè)查詢的詳細(xì)流程
這篇文章主要給大家介紹了關(guān)于Mybatis實(shí)現(xiàn)分頁(yè)查詢的詳細(xì)流程,MyBatis是支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架,需要的朋友可以參考下2023-08-08淺談java中OO的概念和設(shè)計(jì)原則(必看)
下面小編就為大家?guī)?lái)一篇淺談java中OO的概念和設(shè)計(jì)原則(必看)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05解析SpringBoot項(xiàng)目開(kāi)發(fā)之Gzip壓縮過(guò)程
這篇文章主要介紹了SpringBoot項(xiàng)目開(kāi)發(fā)之Gzip壓縮過(guò)程,本文給大家分享幾種Gzip壓縮方式,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07BeanUtils.copyProperties復(fù)制對(duì)象結(jié)果為空的原因分析
這篇文章主要介紹了BeanUtils.copyProperties復(fù)制對(duì)象結(jié)果為空的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Spring mvc工作原理_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Spring mvc工作原理的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08基于Rest的API解決方案(jersey與swagger集成)
下面小編就為大家?guī)?lái)一篇基于Rest的API解決方案(jersey與swagger集成)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08