摘要:撤銷鎖偏向鎖使用了一種等到競爭出現才釋放鎖的機制,所以當其他線程嘗試競爭偏向鎖時,持有偏向鎖的線程才會釋放鎖。輕量級鎖線程在執行同步代碼塊之前,會先在當前線程的棧楨中創建用于存儲鎖記錄的空間,并將對象頭中的復制到鎖記錄中,官方稱為。
前言
作者前面也寫了幾篇關于Java并發編程,以及線程和volatil的基礎知識,有興趣可以閱讀作者的原文博客,今天關于Java中的兩種鎖進行詳解,希望對你有所幫助
</>復制代碼
本文受趙sir原創發布,轉載請聯系原創
https://blog.csdn.net/qq_3609...
為什么使用synchronized
在上一章中說了volatile,在多線程下可以保證變量的可見性,但是不能保證原子性,下面一段代碼說明:
運行上面代碼,會發現輸出flag的值不是理想中10000,雖然volatile寫入時候會通知其他線程的工作內存值無效,從主內存重寫讀取。i++是三步操作,讀取-賦值-寫入不能保證原子性。原子性:不能被中斷要么成功要么失敗。
比如此時主內存的flag值10,線程1和線程2讀取到自己工作內存都是10,然后線程1在進行賦值的時候,線程2執行了,這時線程2發現自己內存的值和主內存的值一樣,并沒有修改,然后賦值寫入11,此時線程1運行,因為之前讀過了,會往下繼續運行寫入也是11。那么兩個線程相當于只增加了一次。要想達到理想值,只需要修改public synchronized void increase() { flag++; }就行了。
什么是synchronizedJava提供的一種原子性性內置鎖,Java每個對象都可以把它當做是監視器鎖,線程代碼執行在進入synchronized代碼塊時候會自動獲取內部鎖,這個時候其他線程訪問時候會被阻塞到隊列,直到進入synchronized中的代碼執行完畢或者拋出異常或者調用了wait方法,都會釋放鎖資源。在進入synchronized會從主內存把變量讀取到自己工作內存,在退出的時候會把工作內存的值寫入到主內存,保證了原子性。
synchronized機制編譯后執行javap -v Test.class就會發現兩條指令。
synchronized是使用一種monitor機制,在進入鎖時候先執行monitorenter指令。退出的時候執行monitorexit指令。synchronized是可重入鎖,每個對象中都含有一個計數器當前線程再次獲取鎖,計數器+1,退出時候計算器-1,直到計數器為0才釋放鎖資源,喚醒其他線程來爭搶資源。任意一個對象都擁有自己的監視器,只有在線程獲取到監視器鎖時才會進入代碼中,否則就進入阻塞狀態。
synchronized使用場景對于普通方法,鎖是當前類實例對象。
對于靜態方法,鎖是當前類對象。
對于同步代碼塊,鎖是synchronized括號里的對象。
synchronized鎖升級synchronized在1.6以前是重量級鎖,當前只有一個線程執行,其他線程阻塞。為了減少獲得鎖和釋放鎖帶來的性能問題,而引入了偏向鎖、輕量級鎖以及鎖的存儲過程和升級過程。在1.6后鎖分為了無鎖、偏向鎖、輕量鎖、重量鎖,鎖的狀態在多線程競爭的情況下會逐漸升級,只能升級而不能降級,這樣是為了提高鎖獲取和釋放的效率。
synchronized的鎖是存貯在Java對象頭里的,如果對象是數組類型,則虛擬機用3個字寬(Word)存儲對象頭,如果對象是非數組類型,則用2字寬存儲對象頭。1個字寬等于4個字節。
Java對象頭中的Mark Word里默認存儲了對象是HashCode、分代年齡、和鎖標記。
在運行的時候,Mark Word里存儲的數據會隨著鎖標志位的變化而變化,可能會變化為存儲以下四種形式。
偏向鎖的意思未來只有一個線程使用鎖,不會有其他線程來爭取。
獲取鎖:
首先檢查Mark word中鎖的標志是否為01。
如果是01,判斷對象頭的Mark word記錄是否為當前線程ID,如果是執行5,否則執行3.
線程ID并未只指向自己,發送CAS競爭,如果競爭成功,則將Mark Word中線程ID設置為當前線程ID,執行5;如果未成功執行4。
當到達全局安全點(在這個時間點上沒有正在執行的字節碼)時獲得偏向鎖的線程被掛起,偏向鎖升級為輕量級鎖,然后被阻塞在安全點的線程繼續往下執行同步代碼。
執行同步代碼。
撤銷鎖:偏向鎖使用了一種等到競爭出現才釋放鎖的機制,所以當其他線程嘗試競爭偏向鎖時,持有偏向鎖的線程才會釋放鎖。需要等待全局安全點,它首先暫停原持有偏向鎖的線程,然后檢查線程是否還在活著,如果線程處于未活動狀態,則釋放鎖標記,如果處于活動狀態則升級為輕量級鎖。
CASCAS全稱是Compare And Swap 即比較并交換,使用樂觀鎖機制,包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。 如果內存位置的值與預期原值相匹配,那么才會將該位置值更新為新值 。否則,處理器不做任何操作。
輕量級鎖線程在執行同步代碼塊之前,JVM會先在當前線程的棧楨中創建用于存儲鎖記錄的空間,并將對象頭中的Mark Word復制到鎖記錄中,官方稱為Displaced Mark Word。
加鎖:
CAS修改Mark Word,如果成功指向棧中鎖記錄的指針執行3,如果失敗執行2.
發生自旋,自旋到一定次數,如果修改成功執行3,否則鎖膨脹為重量級鎖。
執行同步代碼塊。
解鎖:
輕量級解鎖時,會使用原子的CAS操作將Displaced Mark Word替換回到對象頭,如果成功,則表示沒有競爭發生。如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖。
它是在1.5之后提供的一個獨占鎖接口,它的實現類是ReentrantLock,相比較synchronized這種隱式鎖(不用手動加鎖和釋放鎖)的便捷性,但是提供了更加鎖的可操作性、可中斷的獲取鎖以及超時獲取鎖等多種synchronized不具備的特性。
使用方法在finally中釋放鎖,目的保證獲取鎖最終被釋放。不要在獲取鎖寫在try里,因為如果在獲取鎖時發生了異常,異常拋出的同時,也會導致鎖無故釋放。
AQSAQS是隊列同步器(AbstractQueuedSynchronizer),是用來構建鎖或者其他同步器的基礎框架,它使用了一個int成員變量表示同步狀態,通過內置的FIFO隊列來完成資源獲取的線程排隊工作問題。AQS在內部維護了一個單一的狀態信息state,可以通過getState、setState、compareAndSetState(CAS操作)修改此值,對于ReentrantLock來說,state可以用來表示當前線程獲取鎖的可重入次數。ReentrantLock中當一個線程獲取了鎖,在AQS的內部會進行compareAndSetState將state變為1,如果再次獲取就設置為2,釋放鎖也會去修改state值,只有當值變為0時,其他線程才能獲得鎖。
鎖的介紹AQS底層維護state和隊列來實現獨占和共享兩種鎖。
獨占鎖:每次只能有一個線程能持有鎖,如lock、synchronized。
共享鎖:允許多個線程同時獲取鎖,并發訪問共享資源,如ReadWriteLock。
lock分為公平鎖和非公平鎖,實現了AQS接口,通過FIFO設置鎖的優先級。
公平鎖:根據線程獲取鎖的時間來判斷,等待時間越久的線程優先被執行。Lock中初始化的時候ReentrantLock(true),默認為false,效率較低因為需要判斷線程的等待時間。
非公平鎖:搶占鎖資源,不能保證獲取鎖的線程優先級,效率較高,因為獲取鎖是競爭的。
兩者不同synchronized是Java的關鍵字,lock是提供的類。
synchronized提供不需要手動加鎖和釋放的隱式鎖,釋放鎖的條件是代碼執行完或者拋出異常自動釋放。lock必須手動加鎖和釋放鎖,另外還提供了可中斷鎖、超時獲取鎖、判斷鎖狀態。
synchronized是可重入、不可中斷、非公平,lock是可重入、可中斷、公平(兩者皆可)
synchronized適合代碼量少的同步,lock適合代碼量同步多的。**
Condition接口還記得在Java并發二中有一道生產者消費者,使用的是synchronized+wait(notify),lock中也提供了這種等待通知類型的方法await和signal,當前線程調用這些方法時,需要提前獲取到Condition對象關聯的鎖,Condition是依賴于Lock對象,調用lock對象中的newCondition。
老樣子還是先定義一個容器:
生產者:啟5個線程往容器里添加數據。
消費者:啟10線程消費數據
最后注釋基本明確,就不多說了。wait和notify是配合synchronized使用,await和signal是配合lock使用,區別在于喚醒時notify不能指定線程喚醒,signal可以喚醒具體的線程,更小的粒度控制鎖。
閱讀更多金三銀四,2019最新面試實戰總結
如何通過抓包實戰來學習Web協議?
動畫:一招學會TCP的三次握手和四次揮手
上兩個月,15家面試,幾個offer , 我的面試歷程!
相信自己,沒有做不到的,只有想不到的在這里獲得的不僅僅是技術!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77721.html
摘要:為什么叫重入鎖呢,我們把它拆開來看就明了了。釋放鎖,每次鎖持有者數量遞減,直到為止。 相信大家在工作或者面試過程中經常聽到重入鎖這個概念,或者與關鍵字 synchrozied 的對比,棧長面試了這么多人,80%的面試者都沒有答對或沒有答到點上,或者把雙重效驗鎖搞混了,哭笑不得。。 那么你對重入鎖了解有多少呢?今天,棧長幫大家撕開重入鎖的面紗,來見識下重入鎖的真實容顏。。 什么是重入鎖 ...
摘要:記得幾年前有一次棧長去面試,問到了這么一個問題中的對象都是在堆中分配嗎說明為什么當時我被問得一臉蒙逼,瞬間被秒殺得體無完膚,當時我壓根就不知道他在考什么知識點,難道對象不是在堆中分配嗎最后就沒然后了,回去等通知了。。 記得幾年前有一次棧長去面試,問到了這么一個問題: Java中的對象都是在堆中分配嗎?說明為什么! 當時我被問得一臉蒙逼,瞬間被秒殺得體無完膚,當時我壓根就不知道他在考什么...
摘要:算法名稱描述優點缺點標記清除算法暫停除了線程以外的所有線程算法分為標記和清除兩個階段首1 回顧我的時間線 在本文的開頭,先分享一下自己的春招經歷吧: 各位掘友大家好,我是練習時長快一年的Android小蔡雞,喜歡看源碼,逛掘金,寫技術文章...... 好了好,不開玩笑了OWO,今年春招投了許多簡歷的,但是被撈的只有阿里,頭條和美團,一路下來挺不容易的. 個人認為在春招中運氣>性格>三觀>技術...
摘要:所以,剛開始我并沒有直接就投遞阿里,畢竟心里還是有一點點小害怕的。操作系統的內存管理機制進程和線程的區別說下你對線程安全的理解有什么作用,和有什么區別實現原理用過么什么場景下用的底層原理。 作者:ppxyn。本文來自讀者投稿。該文已加入筆主的開源項目——JavaGuide(一份涵蓋大部分Java程序員所需要掌握的核心知識的文檔類項目),地址:https://github.com/Sna...
閱讀 2966·2021-09-23 11:32
閱讀 2932·2021-09-22 15:12
閱讀 1714·2019-08-30 14:07
閱讀 3456·2019-08-29 16:59
閱讀 1646·2019-08-29 11:11
閱讀 2311·2019-08-26 13:50
閱讀 2430·2019-08-26 13:49
閱讀 2625·2019-08-26 11:49