最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java 線程同步詳細(xì)介紹及實(shí)例代碼

 更新時(shí)間:2017年02月19日 14:52:43   投稿:lqh  
這篇文章主要介紹了java 線程同步詳細(xì)介紹及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下

java 線程同步

概要:

為了加快代碼的運(yùn)行速度,我們采用了多線程的方法。并行的執(zhí)行確實(shí)讓代碼變得更加高效,但隨之而來(lái)的問(wèn)題是,有很多個(gè)線程在程序中同時(shí)運(yùn)行,如果它們同時(shí)的去修改一個(gè)對(duì)象,很可能會(huì)造成訛誤的情況,這個(gè)時(shí)候我們需要用一種同步的機(jī)制來(lái)管理這些線程。

(一)競(jìng)爭(zhēng)條件

記得操作系統(tǒng)中,讓我印象很深的有一張圖。上面畫(huà)的是一塊塊進(jìn)程,在這些進(jìn)程里面分了幾個(gè)線程,所有這些線程齊刷刷統(tǒng)一的指向進(jìn)程的資源。Java中也是如此,資源會(huì)在線程間共享而不是每個(gè)線程都有一份獨(dú)立的資源。在這種共享的情況下,很有可能有多個(gè)線程同時(shí)在訪問(wèn)一個(gè)資源,這種現(xiàn)象我們叫做競(jìng)爭(zhēng)條件。

在一個(gè)銀行系統(tǒng)中,每個(gè)線程分別管理一個(gè)賬戶(hù),這些線程可能會(huì)進(jìn)行轉(zhuǎn)賬的操作。
在一個(gè)線程進(jìn)行操作的時(shí)候,他首先,會(huì)把賬戶(hù)余額存放到寄存器中,第二步,它將寄存器中的數(shù)字減少要轉(zhuǎn)出的錢(qián)數(shù),第三步,它將結(jié)果寫(xiě)回余額中。
問(wèn)題在于,這個(gè)線程在執(zhí)行完1、2步時(shí),另外一個(gè)線程被喚醒并且修改了第一個(gè)線程的賬戶(hù)余額值,但是這個(gè)時(shí)候第一個(gè)線程并不知情。第一個(gè)線程等待第二個(gè)線程執(zhí)行完畢后,繼續(xù)他的第三步:將結(jié)果寫(xiě)回余額中。這個(gè)時(shí)候,它把第二個(gè)線程的操作刷掉了,所以整個(gè)的系統(tǒng)的總錢(qián)數(shù)肯定會(huì)發(fā)成錯(cuò)誤。
這就是java競(jìng)爭(zhēng)條件發(fā)生的不良情況。

(二)ReentrantLock類(lèi)

上面的例子告訴我們,如果我們的操作不是原子操作,被打斷是肯定會(huì)發(fā)生的,即使有的時(shí)候概率真的非常小,但是也并不能排除這種情況。我們不能把我們的代碼變成像操作系統(tǒng)中的原子操作,我們能做的是為我們的代碼上鎖來(lái)保證安全性。在并發(fā)程序中,如果我們想要訪問(wèn)數(shù)據(jù),在這之前我們先給我們的代碼套一個(gè)鎖,在我們使用鎖的期間,我們的代碼中涉及的資源就像是被”鎖上了“一樣,不能被其他的線程訪問(wèn),知道我們打開(kāi)這個(gè)鎖。

在java中,synchronized關(guān)鍵字和ReentrantLock類(lèi)都有這種鎖的功能。我們?cè)谶@里首先一起來(lái)討論一下ReentrantLcok的功能。

1.ReentrantLock構(gòu)造器

在這個(gè)類(lèi)中,提供了兩個(gè)構(gòu)造器,一個(gè)是默認(rèn)構(gòu)造器,沒(méi)什么好說(shuō)的,一個(gè)是帶有公平策略的構(gòu)造器。這個(gè)公平策略首先他比正常的鎖要慢很多,其次在有的情況下他并不是真正公平的。而且如果我們沒(méi)有特殊的理由真的需要公平策略的時(shí)候,盡量不要去研究這個(gè)策略。

2.獲取與釋放

ReentrantLock myLock = new ReentrantLock();
//創(chuàng)建對(duì)象
myLock.lock();
//獲取鎖
try{
...
}
finally{
myLock.unlock();
//釋放鎖
}

一定要記得在finally中釋放鎖??!我們之前說(shuō)過(guò),未檢查的錯(cuò)誤會(huì)導(dǎo)致線程的終止。莫名其妙的終止會(huì)讓程序停止向下運(yùn)行,如果不把釋放放在finally中,這個(gè)鎖將一直得不到釋放。這種道理和我們?cè)谄綍r(shí)框架中用包后.close()是一個(gè)道理。說(shuō)到close,值得一提的,當(dāng)我們使用鎖的時(shí)候,我們不能使用“帶有資源的try語(yǔ)句”,因?yàn)檫@個(gè)鎖并不是用close來(lái)關(guān)閉的。如果你不知道帶有資源的try語(yǔ)句是什么,那就當(dāng)我沒(méi)說(shuō)這句話(huà)吧。

3.鎖具有可重入性

如果你要在遞歸或者循環(huán)程序中使用鎖,那么就放心的用吧。ReentrantLock鎖具有可重入性,他會(huì)在每次調(diào)用lock()的時(shí)候維護(hù)一個(gè)計(jì)數(shù)記錄著被調(diào)用的次數(shù),在每一次的lock調(diào)用都必須要用unlock來(lái)釋放。

(三)條件對(duì)象

通常,線程在上了鎖進(jìn)入臨界區(qū)之后發(fā)現(xiàn)了一個(gè)問(wèn)題,他們所需要的資源,在別的對(duì)象中被使用或者并不滿(mǎn)足他們能執(zhí)行的條件,這個(gè)時(shí)候我們需要用一個(gè)條件對(duì)象來(lái)管理這些得到了一個(gè)鎖,但是不能做有用工作的線程。

if(a>b){
  a.set(b-1);
}

1.”自己困住了自己“

上面是一個(gè)很簡(jiǎn)單的條件判斷,但是我們?cè)诓l(fā)程序中不能這樣寫(xiě)。存在的問(wèn)題是,如果在這個(gè)線程剛剛做完判斷之后,另外一個(gè)線程被喚醒,并且另外一個(gè)線程在操作之后使得a小于b(if語(yǔ)句中的條件已經(jīng)不再正確)。

那么這個(gè)時(shí)候我們可能想到,我們把整個(gè)if語(yǔ)句直接放在鎖里面,確保自己的代碼不會(huì)被打斷。但是這樣又存在一個(gè)問(wèn)題,如果if判斷是false,那么if中的語(yǔ)句不會(huì)被執(zhí)行。但是如果我們需要去執(zhí)行if中的語(yǔ)句,甚至我們要一直等待if判斷變的正確之后去執(zhí)行if中的語(yǔ)句,這時(shí),我們突然發(fā)現(xiàn),if語(yǔ)句再也不會(huì)變得正確了,因?yàn)槲覀兊逆i把這個(gè)線程鎖死,其他的線程沒(méi)辦法訪問(wèn)臨界區(qū)并修改a和b的值讓if判斷變得正確,這真的是非常尷尬,我們自己的鎖把我們自己困住了,我們出不去,別人進(jìn)不來(lái)。

2.Condition類(lèi)

為了解決這種情況,我們用ReentrantLock類(lèi)中的newCondition方法來(lái)獲取一個(gè)條件對(duì)象。

Condition cd = myLock.newCondition();

獲取了Condition對(duì)象之后,我們就應(yīng)該來(lái)研究這個(gè)對(duì)象有什么方法和作用了。先不急于看API,我們回到主題發(fā)現(xiàn)現(xiàn)在亟待解決的就是if條件判斷的問(wèn)題,我們?nèi)绾尾拍埽?strong>在已經(jīng)上鎖的情況下,發(fā)現(xiàn)if判斷錯(cuò)誤時(shí),給其他線程機(jī)會(huì)并自己一直等著if判斷變回正確。

Condition類(lèi)就是為了解決這個(gè)難題而生的,有了Condition類(lèi)之后,我們?cè)趇f語(yǔ)句下面直接跟上await方法,這個(gè)方法表示這個(gè)線程被阻塞,并放棄了鎖,等其他的線程來(lái)操作。

注意在這里我們用的名詞是阻塞,我們之前也說(shuō)過(guò)阻塞和等待有很大不同:等待獲得鎖時(shí),一旦鎖有了空閑,他可以自動(dòng)的去獲得鎖,而阻塞獲得鎖時(shí),即使有空閑的鎖,也要等待線程調(diào)度器允許他去持有鎖的時(shí)候才能獲得鎖。

其他的線程在順利執(zhí)行if語(yǔ)句內(nèi)容之后,要去調(diào)用signalAll方法,這個(gè)方法將會(huì)重新去激活所有的因?yàn)檫@個(gè)條件被阻塞的線程,讓這些線程重新獲得機(jī)會(huì),這些線程被允許從被阻塞的地方繼續(xù)進(jìn)行。此時(shí),線程應(yīng)該再次測(cè)試該條件,如果還是不能滿(mǎn)足條件,需要再次重復(fù)上述操作。

ReentrantLock myLock = new ReentrantLock();
//創(chuàng)建鎖對(duì)象
myLock.lock();
//給下面的臨界區(qū)上鎖

Condition cd = myLock.newCondition();
//創(chuàng)建一個(gè)Condition對(duì)象,這個(gè)cd對(duì)象表示條件對(duì)象

while(!(a>b))
  cd.await();
//上面的while循環(huán)和await方法調(diào)用是標(biāo)準(zhǔn)寫(xiě)法
//如果不能滿(mǎn)足if的條件,那么他將進(jìn)入阻塞狀態(tài),放棄鎖,等待別人去激活它

a.set(b-1);
//一直等到從while循環(huán)出來(lái),滿(mǎn)足了判斷的條件,我們執(zhí)行自己的功能

cd.signalAll();
//最后一定不能忘記調(diào)用signalAll方法去激活其他的被阻塞的線程
//如果所有的線程都在等待其他線程signalAll,則進(jìn)入死鎖


非常不妙的,如果所有的線程都在等待其他線程signalAll,則進(jìn)入死鎖的狀態(tài)。死鎖狀態(tài)是指所有的線程需要的資源都被其他的線程形成環(huán)狀結(jié)構(gòu)而導(dǎo)致誰(shuí)都不能執(zhí)行的情況。最后調(diào)用signalAll方法激活其他因?yàn)閏d而阻塞的“兄弟”是必須的,方便你我他,減少死鎖的發(fā)生。

3.Condition對(duì)象和鎖總結(jié)

總結(jié)來(lái)說(shuō),Condition對(duì)象和鎖有這樣幾個(gè)特點(diǎn)。

  1. 鎖可以用來(lái)保護(hù)代碼片段,任何時(shí)刻只能有一個(gè)線程進(jìn)入被保護(hù)的區(qū)域
  2. 鎖可以管理試圖進(jìn)入臨界區(qū)的線程
  3. 鎖可以擁有一個(gè)或多個(gè)條件對(duì)象
  4. 每個(gè)條件對(duì)象管理那些因?yàn)榍懊嫠枋龅脑蚨荒鼙粓?zhí)行但已經(jīng)進(jìn)入被保護(hù)代碼段的線程

(四)synchronized關(guān)鍵字

我們上面介紹的ReentrantLock和Condition對(duì)象是一種用來(lái)保護(hù)代碼片段的方法,在java中還有另外一種機(jī)制:通過(guò)使用關(guān)鍵字synchronized來(lái)修飾方法,從而給方法添加一個(gè)內(nèi)部鎖。從版本開(kāi)始,java的每一個(gè)對(duì)象都有一個(gè)內(nèi)部鎖,每個(gè)內(nèi)部鎖會(huì)保護(hù)那些被synchronized修飾的方法。也就是說(shuō),如果想調(diào)用這個(gè)方法,首先要獲得內(nèi)部的對(duì)象鎖。

1.synchronized與ReentrantLock比較

我們先拿出上面的代碼:

public void function(){
  ReentrantLock myLock = new ReentrantLock();
  myLock.lock();

  Condition cd = myLock.newCondition();

  while(!(a>b))
    cd.await();

  a.set(b-1);

  cd.signalAll();
}

如果我們用synchronized來(lái)實(shí)現(xiàn)這段代碼,將會(huì)變成下面的樣子:

public synchronized void function(){
  while(!(a>b))
    wait();

  a.set(b-1);

  notifyAll();
}

需要我們注意的是,在使用synchronized關(guān)鍵詞時(shí),無(wú)需再去用ReentrantLock和Condition對(duì)象,我們用wait方法替換了await方法,notifyAll方法替換了signalAll方法。這樣寫(xiě)確實(shí)比之前的簡(jiǎn)單了很多。

2.靜態(tài)方法的synchronized

將靜態(tài)方法聲明為synchronized也是合法的。如果調(diào)用這種方法,將會(huì)獲取相關(guān)的類(lèi)對(duì)象的內(nèi)部鎖。比如我們調(diào)用Test類(lèi)中的靜態(tài)方法,這時(shí),Test.class對(duì)象的鎖將被鎖住。

3.內(nèi)部鎖和條件的局限性

內(nèi)部鎖雖然簡(jiǎn)便,但是他存在著很多限制:

  1. 不能中斷一個(gè)正在試圖獲得鎖的線程
  2. 試圖獲得鎖時(shí)不能設(shè)定超時(shí)
  3. 因?yàn)椴荒芡ㄟ^(guò)Condition來(lái)實(shí)例化條件。每個(gè)鎖僅有單一的條件,可能是不夠的

在代碼中應(yīng)該使用這兩種鎖中的哪一種呢?Lock和Condition對(duì)象還是同步方法?在core java一書(shū)中有一些建議:

  1. 最好既不使用ReentrantLock也不使用synchronized關(guān)鍵詞。在許多情況下你可以使用java.util.concurrent包
  2. 如果synchronized符合你的代碼需要,請(qǐng)優(yōu)先使用它
  3. 直到如果特別需要ReentrantLcok,再去使用它

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • 在Java內(nèi)存模型中測(cè)試并發(fā)程序代碼

    在Java內(nèi)存模型中測(cè)試并發(fā)程序代碼

    這篇文章主要介紹了在Java內(nèi)存模型中測(cè)試并發(fā)程序代碼,輔以文中所提到的JavaScript庫(kù)JCStress進(jìn)行,需要的朋友可以參考下
    2015-07-07
  • Java String類(lèi)常用方法梳理總結(jié)

    Java String類(lèi)常用方法梳理總結(jié)

    這篇文章主要介紹了Java String類(lèi)常用方法梳理總結(jié),類(lèi) String 中包括用于檢查各個(gè)字符串的方法,比如用于比較字符串,搜索字符串,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-06-06
  • springBoot系列常用注解(小結(jié))

    springBoot系列常用注解(小結(jié))

    這篇文章主要介紹了springBoot系列常用注解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java object類(lèi)及正則表達(dá)式原理解析

    Java object類(lèi)及正則表達(dá)式原理解析

    這篇文章主要介紹了Java object類(lèi)及正則表達(dá)式原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Mybatis實(shí)現(xiàn)關(guān)聯(lián)關(guān)系映射的方法示例

    Mybatis實(shí)現(xiàn)關(guān)聯(lián)關(guān)系映射的方法示例

    本文主要介紹了Mybatis實(shí)現(xiàn)關(guān)聯(lián)關(guān)系映射的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • SpringBoot集成Swagger2生成接口文檔的方法示例

    SpringBoot集成Swagger2生成接口文檔的方法示例

    我們提供Restful接口的時(shí)候,API文檔是尤為的重要,它承載著對(duì)接口的定義,描述等,本文主要介紹了SpringBoot集成Swagger2生成接口文檔的方法示例,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • Java工具類(lèi)Hutool、Guava與Apache?Commons的區(qū)別詳解

    Java工具類(lèi)Hutool、Guava與Apache?Commons的區(qū)別詳解

    Hutool?和?Guava?都是?Java?開(kāi)發(fā)中非常實(shí)用的工具庫(kù),它們提供了許多方便的工具類(lèi)和方法,簡(jiǎn)化了常見(jiàn)的編程任務(wù),這篇文章主要介紹了Java工具類(lèi)Hutool、Guava與Apache?Commons區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2025-10-10
  • Java中StringBuilder類(lèi)常用方法總結(jié)

    Java中StringBuilder類(lèi)常用方法總結(jié)

    這篇文章主要介紹了Java中StringBuilder類(lèi)常用方法的相關(guān)資料,StringBuilder類(lèi)是Java中用于頻繁修改字符串的可變字符串緩沖區(qū)類(lèi),它提供了多種方法進(jìn)行字符串操作,如添加、插入、刪除、替換字符等,需要的朋友可以參考下
    2024-12-12
  • 一文詳解Java對(duì)象的序列化和反序列化

    一文詳解Java對(duì)象的序列化和反序列化

    本文主要介紹了一文詳解Java對(duì)象的序列化和反序列化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Maven打包jar包沒(méi)有主屬性問(wèn)題解決方案

    Maven打包jar包沒(méi)有主屬性問(wèn)題解決方案

    這篇文章主要介紹了Maven打包jar包沒(méi)有主屬性問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07

最新評(píng)論

大足县| 洪泽县| 临安市| 响水县| 鄂尔多斯市| 宿州市| 高州市| 叶城县| 岢岚县| 长泰县| 沂源县| 清新县| 朝阳市| 阿勒泰市| 东丰县| 察雅县| 襄垣县| 阜南县| 镇坪县| 卓尼县| 盱眙县| 桐庐县| 福建省| 延安市| 四川省| 广州市| 北辰区| 巢湖市| 松滋市| 互助| 稻城县| 刚察县| 邵武市| 梨树县| 东丰县| 保德县| 徐汇区| 安仁县| 依兰县| 青川县| 太原市|