JAVA多線程機制解析-volatile&synchronized

java代碼先編譯成字節碼,字節碼最後編譯成cpu指令,所以Java的多線程實現最終依賴於jvm和cpu的實現java

synchronized和volatile

咱們先來討論一下volatile關鍵字的做用以及實現機制,每一個線程看到的用volatile修飾的變量的值都是最新的,更深刻的解釋就涉及到Java的內存模型了,咱們知道Java將內存分爲主內存和線程私有內存,全部的全局變量都在主內存中,每一個線程使用變量時都會從主內存中讀取變量,而後放到各自線程的私有內存中,這樣線程使用變量時就不用每次都去讀取主內存了,固然這也產生了一個問題,若是線程修改了變量值,可是修改的值沒有及時地同步到主內存中,那麼其餘線程看到的變量值仍然是未修改以前的值,這就產生了併發問題,而當這個變量用volatile修飾後,每次線程都會從主內存中讀取變量值,也就是說拋棄了線程私有內存中的變量值,而線程每次修改變量後,就會將修改後的值同步到主內存中去。編程

理論上volatile就是這麼實現滴,可是volatile最終會被編譯成機器指令,因此volatile這種機制也須要相關的機器指令支持,學習過計算機組成原理的同窗們都知道計算機在cpu和主內存直接有一個cache緩存,是否是和Java模型很相似,固然還不同,其實volatile最終使用了cpu緩存一致性也就是說將緩存中的內容馬上更新到主內存中去,同時將其餘緩存中的值置爲無效。若是你們有探索精神能夠看看看看volatile被編程爲的彙編代碼,就會發現volatile是用Lock信號實現地。緩存

下面咱們再來講說synchronized關鍵字,學習過Java的同窗應該都知道這個關鍵字是用來實現多線程同步的,synchronized的具體用法這裏就不介紹了,咱們來聊下這個關鍵字的具體實現,看過Java併發的同窗都會發現synchronized被稱爲重量級鎖,怎麼理解這個重量級的概念那?反正個人理解是加鎖解鎖耗費地時間多,致使併發度比較低唄,可是隨着JDK版本的升級,synchronized的性能和併發庫中Lock的性能基本持平。好了言歸正傳,synchronized的具體實現不知道同窗們瞭解多少,我想大部分人應該能說出synchronized由一個同步隊列和對象監視器實現,線程進入同步塊時,先獲取監視器若是成功就進入同步塊,若是不成功就進入同步隊列等待另一個線程從同步塊退出,沒錯這就是synchronized的實現,若是你只知道這些說明你瞭解的還不夠深刻,由於你還須要知道偏向鎖、輕量級鎖和synchronized的關係,在這裏我就拋磚引玉先說說我本身的理解吧,咱們都知道一個Java對象有三部分組成,對象頭,實體部分,對齊填充部分,這個對象頭就是實現synchronized的關鍵,在比較老的JDK版本中,一個線程進入同步代碼塊時就要獲取互斥量,無論有沒有其餘線程,改進後的synchronized,線程通常先獲取偏向鎖,若是有競爭就膨脹爲輕量級鎖或者重量級鎖,輕量級鎖又會膨脹爲重量級鎖,那麼偏向鎖、輕量級鎖、重量級鎖有什麼區別那?安全

偏向鎖:多線程

對象頭中設置偏向鎖標記,同時將當前線程的線程id保存在對象頭和棧的鎖記錄空間中;併發

輕量級鎖jvm

將對象頭的內容複製到當前線程棧的鎖記錄空間中,同時將對象頭設置爲指向鎖記錄空間的指針;性能

重量級鎖
將對象頭的內容複製到當前線程的鎖記錄空間中,同時將對象頭設置爲指向互斥量的指針;學習

當一個線程進入同步快時,先經過cas設置對象頭爲偏向鎖,若設置成功則說明線程獲取鎖,若設置不成功,說明鎖存在競爭,持有偏向鎖的線程就要釋放偏向鎖,偏向鎖膨脹爲輕量級鎖或重量級鎖。
當一個線程持有輕量級鎖,另一個線程嘗試獲取鎖,獲取失敗,則另一個線程會自旋等待,若等待一段時間仍未獲取鎖,則線程進入等待,持有輕量級鎖的線程就會在安全點處釋放輕量級鎖,輕量級鎖也會膨脹爲重量級鎖。
當一個線程持有重量級鎖時,另一個線程就會被直接踢到同步隊列中等待。線程

(安全點是jvm的一些特殊位置,在這個位置上全部的線程都會暫停工做,通常在安全點處進行垃圾回收,還有一個概念是安全區域,安全區域是指在一塊代碼內引用關係不會發生變化,這個代碼的任何位置進行垃圾回收都是能夠的)

相關文章
相關標籤/搜索