久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java中的鎖原理、鎖優(yōu)化,、CAS,、AQS

 黃家v少 2018-04-08

一、為什么要用鎖,?

鎖-是為了解決并發(fā)操作引起的臟讀,、數(shù)據(jù)不一致的問題。

二,、鎖實現(xiàn)的基本原理

2.1,、volatile

Java編程語言允許線程訪問共享變量, 為了確保共享變量能被準確和一致地更新,,線程應(yīng)該確保通過排他鎖單獨獲得這個變量,。Java語言提供了volatile,在某些情況下比鎖要更加方便,。

volatile在多處理器開發(fā)中保證了共享變量的“ 可見性”,。可見性的意思是當(dāng)一個線程修改一個共享變量時,,另外一個線程能讀到這個修改的值,。

結(jié)論:如果volatile變量修飾符使用恰當(dāng)?shù)脑挘萻ynchronized的使用和執(zhí)行成本更低,,因為它不會引起線程上下文的切換和調(diào)度,。

2.2、synchronized

synchronized通過鎖機制實現(xiàn)同步,。

先來看下利用synchronized實現(xiàn)同步的基礎(chǔ):Java中的每一個對象都可以作為鎖,。

具體表現(xiàn)為以下3種形式。

  • 對于普通同步方法,,鎖是當(dāng)前實例對象,。

  • 對于靜態(tài)同步方法,鎖是當(dāng)前類的Class對象,。

  • 對于同步方法塊,,鎖是Synchonized括號里配置的對象。

當(dāng)一個線程試圖訪問同步代碼塊時,,它首先必須得到鎖,,退出或拋出異常時必須釋放鎖。

2.2.1 synchronized實現(xiàn)原理

synchronized是基于Monitor來實現(xiàn)同步的,。

Monitor從兩個方面來支持線程之間的同步:

  • 互斥執(zhí)行

  • 協(xié)作

1,、Java 使用對象鎖 ( 使用 synchronized 獲得對象鎖 ) 保證工作在共享的數(shù)據(jù)集上的線程互斥執(zhí)行。

2,、使用 notify/notifyAll/wait 方法來協(xié)同不同線程之間的工作,。

3、Class和Object都關(guān)聯(lián)了一個Monitor,。

Monitor 的工作機理

  • 線程進入同步方法中,。

  • 為了繼續(xù)執(zhí)行臨界區(qū)代碼,線程必須獲取 Monitor 鎖,。如果獲取鎖成功,,將成為該監(jiān)視者對象的擁有者。任一時刻內(nèi),,監(jiān)視者對象只屬于一個活動線程(The Owner)

  • 擁有監(jiān)視者對象的線程可以調(diào)用 wait() 進入等待集合(Wait Set),,同時釋放監(jiān)視鎖,,進入等待狀態(tài)。

  • 其他線程調(diào)用 notify() / notifyAll() 接口喚醒等待集合中的線程,,這些等待的線程需要重新獲取監(jiān)視鎖后才能執(zhí)行 wait() 之后的代碼,。

  • 同步方法執(zhí)行完畢了,線程退出臨界區(qū),,并釋放監(jiān)視鎖,。

參考文檔:https://www.ibm.com/developerworks/cn/java/j-lo-synchronized

2.2.2 synchronized具體實現(xiàn)

1、同步代碼塊采用monitorenter,、monitorexit指令顯式的實現(xiàn),。

2、同步方法則使用ACC_SYNCHRONIZED標記符隱式的實現(xiàn),。

通過實例來看看具體實現(xiàn):

javap編譯后的字節(jié)碼如下:

monitorenter

每一個對象都有一個monitor,,一個monitor只能被一個線程擁有。當(dāng)一個線程執(zhí)行到monitorenter指令時會嘗試獲取相應(yīng)對象的monitor,,獲取規(guī)則如下:

  • 如果monitor的進入數(shù)為0,,則該線程可以進入monitor,并將monitor進入數(shù)設(shè)置為1,,該線程即為monitor的擁有者,。

  • 如果當(dāng)前線程已經(jīng)擁有該monitor,只是重新進入,,則進入monitor的進入數(shù)加1,,所以synchronized關(guān)鍵字實現(xiàn)的鎖是可重入的鎖。

  • 如果monitor已被其他線程擁有,,則當(dāng)前線程進入阻塞狀態(tài),,直到monitor的進入數(shù)為0,再重新嘗試獲取monitor,。

monitorexit

只有擁有相應(yīng)對象的monitor的線程才能執(zhí)行monitorexit指令,。每執(zhí)行一次該指令monitor進入數(shù)減1,當(dāng)進入數(shù)為0時當(dāng)前線程釋放monitor,,此時其他阻塞的線程將可以嘗試獲取該monitor,。

2.2.3 鎖存放的位置

鎖標記存放在Java對象頭的Mark Word中。

Java對象頭長度

32位JVM Mark Word 結(jié)構(gòu)

32位JVM Mark Word 狀態(tài)變化

64位JVM Mark Word 結(jié)構(gòu)

2.2.3 synchronized的鎖優(yōu)化

JavaSE1.6為了減少獲得鎖和釋放鎖帶來的性能消耗,,引入了“偏向鎖”和“輕量級鎖”,。

在JavaSE1.6中,鎖一共有4種狀態(tài),,級別從低到高依次是:無鎖狀態(tài),、偏向鎖狀態(tài)、輕量級鎖狀態(tài)和重量級鎖狀態(tài),這幾個狀態(tài)會隨著競爭情況逐漸升級,。

鎖可以升級但不能降級,,意味著偏向鎖升級成輕量級鎖后不能降級成偏向鎖。這種鎖升級卻不能降級的策略,,目的是為了提高獲得鎖和釋放鎖的效率,。

偏向鎖:

無鎖競爭的情況下為了減少鎖競爭的資源開銷,引入偏向鎖,。

輕量級鎖:

輕量級鎖所適應(yīng)的場景是線程交替執(zhí)行同步塊的情況。

鎖粗化(Lock Coarsening):也就是減少不必要的緊連在一起的unlock,,lock操作,,將多個連續(xù)的鎖擴展成一個范圍更大的鎖。

鎖消除(Lock Elimination):鎖削除是指虛擬機即時編譯器在運行時,,對一些代碼上要求同步,,但是被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進行削除。

適應(yīng)性自旋(Adaptive Spinning):自適應(yīng)意味著自旋的時間不再固定了,,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態(tài)來決定,。如果在同一個鎖對象上,自旋等待剛剛成功獲得過鎖,,并且持有鎖的線程正在運行中,,那么虛擬機就會認為這次自旋也很有可能再次成功,進而它將允許自旋等待持續(xù)相對更長的時間,,比如100個循環(huán),。另一方面,如果對于某個鎖,,自旋很少成功獲得過,,那在以后要獲取這個鎖時將可能省略掉自旋過程,以避免浪費處理器資源,。

2.2.4 鎖的優(yōu)缺點對比

2.3,、CAS

CAS,在Java并發(fā)應(yīng)用中通常指CompareAndSwap或CompareAndSet,,即比較并交換,。

1、CAS是一個原子操作,,它比較一個內(nèi)存位置的值并且只有相等時修改這個內(nèi)存位置的值為新的值,,保證了新的值總是基于最新的信息計算的,如果有其他線程在這期間修改了這個值則CAS失敗,。CAS返回是否成功或者內(nèi)存位置原來的值用于判斷是否CAS成功,。

2、JVM中的CAS操作是利用了處理器提供的CMPXCHG指令實現(xiàn)的。

優(yōu)點:

  • 競爭不大的時候系統(tǒng)開銷小,。

缺點:

  • 循環(huán)時間長開銷大,。

  • ABA問題。

  • 只能保證一個共享變量的原子操作,。

三,、Java中的鎖實現(xiàn)

3.1、隊列同步器(AQS)

隊列同步器AbstractQueuedSynchronizer(以下簡稱同步器),,是用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架,。

3.1.1、它使用了一個int成員變量表示同步狀態(tài),。

3.1.2,、通過內(nèi)置的FIFO雙向隊列來完成獲取鎖線程的排隊工作。

  • 同步器包含兩個節(jié)點類型的應(yīng)用,,一個指向頭節(jié)點,,一個指向尾節(jié)點,未獲取到鎖的線程會創(chuàng)建節(jié)點線程安全(compareAndSetTail)的加入隊列尾部,。同步隊列遵循FIFO,,首節(jié)點是獲取同步狀態(tài)成功的節(jié)點。

  • 未獲取到鎖的線程將創(chuàng)建一個節(jié)點,,設(shè)置到尾節(jié)點,。如下圖所示:

  • 首節(jié)點的線程在釋放鎖時,將會喚醒后繼節(jié)點,。而后繼節(jié)點將會在獲取鎖成功時將自己設(shè)置為首節(jié)點,。如下圖所示:

3.1.3、獨占式/共享式鎖獲取

獨占式:有且只有一個線程能獲取到鎖,,如:ReentrantLock,;

共享式:可以多個線程同時獲取到鎖,如:CountDownLatch,;

獨占式

  • 每個節(jié)點自旋觀察自己的前一節(jié)點是不是Header節(jié)點,,如果是,就去嘗試獲取鎖,。

  • 獨占式鎖獲取流程:

共享式:

  • 共享式與獨占式的區(qū)別:

  • 共享鎖獲取流程:

四,、鎖的使用用例

4.1、ConcurrentHashMap的實現(xiàn)原理及使用

ConcurrentHashMap類圖

ConcurrentHashMap數(shù)據(jù)結(jié)構(gòu)

結(jié)論:ConcurrentHashMap使用的鎖分段技術(shù),。首先將數(shù)據(jù)分成一段一段地存儲,,然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個線程占用鎖訪問其中一個段數(shù)據(jù)的時候,,其他段的數(shù)據(jù)也能被其他線程訪問,。

作者景小財

鏈接:https://www.jianshu.com/p/e674ee68fd3f

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多