成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Synchronized 天天用,實現原理你懂嗎?

開發(fā) 后端
Synchronized 關鍵字算是Java的元老級鎖了,一開始它撐起了Java的同步任務,其用法簡單粗暴容易上手。但是有些與它相關的知識點還是需要我們開發(fā)者去深入掌握的。

Synchronized 關鍵字算是Java的元老級鎖了,一開始它撐起了Java的同步任務,其用法簡單粗暴容易上手。但是有些與它相關的知識點還是需要我們開發(fā)者去深入掌握的。

比如,我們都知道通過 Synchronized 鎖來實現互斥功能,可以用在方法或者代碼塊上,那么不同用法都是怎么實現的,以及都經歷了了哪些優(yōu)化等等問題都需要我們扎實的理解。

[[338885]]

一、基本用法

通常我們可以把 Synchronized 用在一個方法或者代碼塊里,方法又有普通方法或者靜態(tài)方法。

對于普通同步方法,鎖是當前實例對象,也就是this

  1. public class TestSyn{ 
  2.   private int i=0
  3.   public synchronized void incr(){ 
  4.     i++; 
  5.   } 

對于靜態(tài)同步方法,鎖是Class對象

  1. public class TestSyn{ 
  2.   private static int i=0
  3.   public static synchronized void incr(){ 
  4.     i++; 
  5.   } 
  6. }   

對于同步代碼塊,鎖是同步代碼塊里的對象

  1. public class TestSyn{ 
  2.   private  int i=0
  3.   Object o = new Object(); 
  4.   public  void incr(){ 
  5.     synchronized(o){ 
  6.         i++; 
  7.     } 
  8.   } 

二、實現原理

在JVM規(guī)范中介紹了 Synchronized 的實現原理,JVM基于進入和退出Monitor對象來實現方法同步和代碼塊同步,但兩者的實現細節(jié)不一樣。

代碼塊同步是使用monitorenter和monitorexit指令實現的,而方法同步是使用另外一種方式實現的,通過一個方法標志(flag) ACC_SYNCHRONIZED來實現的。

1. 同步代碼塊的實現

(1) monitorenter 和 monitorexit

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.monitorenter (參考來源)

下面看下JVM規(guī)范里對moniterenter 和 monitorexit的介紹:

Each object has a monitor associated with it. The thread that executes monitorenter gains ownership of the monitor associated with objectref. If another thread already owns the monitor associated with objectref, the current thread waits until the object is unlocked,

每個對象都有一個監(jiān)視器(Moniter)與它相關聯(lián),執(zhí)行moniterenter指令的線程將獲得與objectref關聯(lián)的監(jiān)視器的所有權,如果另一個線程已經擁有與objectref關聯(lián)的監(jiān)視器,則當前線程將等待直到對象被解鎖為止。

A monitorenter instruction may be used with one or more monitorexit instructions to implement a synchronized statement in the Java programming language. The monitorenter and monitorexit instructions are not used in the implementation of synchronized methods

重點來了,上面這段介紹了兩點:

  • 通過monitorenter和monitorexit指令來實現Java語言的同步代碼塊(后面有代碼示例)
  • monitorenter和monitorexit指令沒有被用在同步方法上!!!

Synchronized 天天用,實現原理你懂嗎?

2. 同步方法的實現

先看下JVM規(guī)范里怎么說的:

https://docs.oracle.com/javase/specs/jvms/se6/html/Compiling.doc.html#6530 (參考來源)

A synchronized method is not normally implemented using monitorenter and monitorexit. Rather, it is simply distinguished in the runtime constant pool by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions. When invoking a method for which ACC_SYNCHRONIZED is set, the current thread acquires a monitor, invokes the method itself, and releases the monitor whether the method invocation completes normally or abruptly.

上面這段話主要講了幾點:

  • 同步方法的實現不是基于monitorenter和monitorexit指令來實現的
  • 在運行時常量池里通過ACC_SYNCHRONIZED來區(qū)分是否是同步方法,方法執(zhí)行時會檢查該標志
  • 當一個方法有這個標志的時候,進入的線程首先需要獲得監(jiān)視器才能執(zhí)行該方法
  • 方法結束或者拋異常時會釋放監(jiān)視器
  1. public class TestSyn { 
  2.  
  3.     private int i=0
  4.     // 同步方法 
  5.     public synchronized void incer(){ 
  6.         i++; 
  7.     } 
  8.     // 同步代碼塊 
  9.     public  void decr(){ 
  10.         synchronized (this) { 
  11.             i--; 
  12.         } 
  13.     } 

可以通過反編譯字節(jié)碼來查看底層是怎么實現的

  1. // 得到字節(jié)碼 
  2. javac TestSyn.java 
  1. // 反編譯字節(jié)碼 
  2. javap -v TestSyn.class 

同步代碼塊的反編譯結果如下:

Synchronized 天天用,實現原理你懂嗎?

同步方法的反編譯結果如下:

Synchronized 天天用,實現原理你懂嗎?

三、鎖升級

1. Java對象頭介紹

(1) 對象的內存布局

在我們常見的HotSpot虛擬機中對象由三部分組成,分別是對象頭,實例數據,以及對齊填充位。

其中對象頭是跟鎖信息相關的部分,在對象頭里會存儲該對象運行時數據,包括哈希碼,GC分代年齡,鎖狀態(tài)(無鎖,偏向鎖,輕量級鎖,重量級鎖),是否偏向鎖,偏向線程ID等信息。

存儲上述這些的區(qū)域叫做Mark Word(標記詞),除了這部分對象頭還有一部分區(qū)域用來存儲類型指針,可以通過該類型指針來定位對象的元數據信息。下面重點看下,對象頭的內存布局,因為這部分是跟我們這次相關的。

對象在內存中的表示如下圖:

Synchronized 天天用,實現原理你懂嗎?

對象頭的結構表示如下圖:

Synchronized 天天用,實現原理你懂嗎?

mark word的表示如下圖:

Synchronized 天天用,實現原理你懂嗎?

2. 什么是鎖升級

下面舉個搶茅坑的例子來解釋一下鎖升級過程。

(1) 當只有一個線程訪問時叫做偏向鎖

假設我們每個廁所都有一把鑰匙,要想使用廁所首先必須得獲得鎖。某天上午員工甲急急忙忙的打完卡上廁所了,并在廁所門上貼了 “工號007使用中”的標簽,說明目前被工號007(相當于線程id)的員工占用呢,他再次向進入的時候只要上面的標簽還顯示工號007,他自己可以隨便進入,不需要再次上鎖了,有點偏向工號007員工的意思,所以這叫偏向鎖。

(2) 發(fā)生競爭的時候升級成輕量級鎖 (自旋等待)

員工甲正在使用廁所的時候,又來了兩個人想用廁所,但發(fā)現廁所被人使用著呢,無法獲得鎖。所以只能在外面等著甲出來,他們等的過程叫做“自旋”,這個叫做輕量級鎖。

那么又有一個問題,當甲出來之后正等著的那兩個人誰活得鎖呢?有兩種方式,按到達的順序來排隊或者不排隊,這兩種都可以實現,前者叫做公平鎖,后者叫做非公平鎖。

(3) 自旋等待沒結果的時候升級成重量級鎖

但那兩個人自旋一段時間之后發(fā)現甲還沒出來(JDK1.6規(guī)定為10次),一直這么等也不是個法子啊,所以打算向上升級,找?guī)芾韱T(操作系統(tǒng))反饋,升級成了重量級鎖了。

鎖的狀態(tài)總共有四種,無鎖狀態(tài)、偏向鎖、輕量級鎖和重量級鎖。隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖。另外關注公眾號Java技術?;貜蚃VM46獲取一份46頁的JVM調優(yōu)教程。

Synchronized 天天用,實現原理你懂嗎?

鎖升級過程中mark word的變化如下:

Synchronized 天天用,實現原理你懂嗎?

(4) 偏向鎖

偏向鎖也是JDK 1.6中引入的一項鎖優(yōu)化, 引入它是為了優(yōu)化在沒有鎖競爭場景下的鎖消除。比如一段同步代碼一直是由單個線程調用,在這種場景下就沒必要使用同步鎖了,這里指的同步鎖不是指 synchronized,而是說沒不要到操作系統(tǒng)層面的互斥量了。

偏向鎖的偏向是指該同步代碼會一直偏向第一個調用它的線程,直到有別的線程過來競爭這把鎖,在第一次調用同步代碼并獲得鎖時會在對象頭和棧幀鎖記錄行(Lock Record)里存儲偏向線程Id,該線程在此進入的時候就不需要重新申請鎖了。只需檢測對象頭的Mark Word里是否存儲著指向該線程的ID即可。

直到又有線程來競爭這把鎖的時候偏向鎖會撤銷偏向。

Synchronized 天天用,實現原理你懂嗎?

Synchronized 天天用,實現原理你懂嗎?

(5) 輕量級鎖

輕量級鎖是JDK 1.6之中加入的新型鎖機制, 它名字中的“輕量級”是相對于使用操作系統(tǒng)。

互斥量來實現的傳統(tǒng)鎖而言的, 因此傳統(tǒng)的鎖機制就稱為“重量級”鎖。它并不是用來代替重量級鎖的, 它的本意是在統(tǒng)的重量級鎖使用操作系統(tǒng)互斥量產生的性能消耗。

線程在執(zhí)行同步塊之前,JVM會先在當前線程的棧楨中創(chuàng)建用于存儲鎖記錄的空間,并將對象頭中的Mark Word復制到鎖記錄中,官方稱為Displaced Mark Word。

然后線程嘗試使用CAS將對象頭中的Mark Word替換為指向鎖記錄的指針。如果成功,當前線程獲得鎖,如果失敗,表示其他線程競爭鎖,當前線程便嘗試使用自旋來獲取鎖.一直原地自旋,如果自旋數達到10次了則升級為重量級鎖。

(6) 重量級鎖

競爭的線程自旋一段時間未能獲取鎖之后會升級為重量級鎖,這個時候鎖的獲取與釋放都會由操作系統(tǒng)來分配了,如果持有鎖的線程釋放鎖之后操作系統(tǒng)會喚醒所有阻塞的那些線程,并進入新一輪的爭搶模式,需要注意的是這些阻塞的線程沒有獲得鎖的優(yōu)先級,也就是說synchronized鎖是非公平的。

除此之外synchronized對中斷操作也是無感的,不會因為被中斷而放棄阻塞等待,它要么得到鎖要么一直阻塞。

 

責任編輯:趙寧寧 來源: 博客園
相關推薦

2019-09-06 09:11:36

以太網數據二層交換

2017-12-06 16:28:48

Synchronize實現原理

2021-01-08 08:34:09

Synchronize線程開發(fā)技術

2021-07-04 08:01:30

Synchronize線程安全并發(fā)編程

2025-03-20 06:48:55

性能優(yōu)化JDK

2022-12-26 09:27:48

Java底層monitor

2019-11-28 10:45:28

ZooKeeper源碼分布式

2019-09-09 09:30:59

Git行程Linux

2015-05-26 11:10:45

沃爾瑪OpenStack

2019-09-03 09:19:34

CPU架構內核

2020-12-29 16:55:44

ZooKeeper運維數據結構

2017-02-27 10:43:07

Javasynchronize

2010-08-29 21:09:57

DHCP協(xié)議

2021-01-11 15:02:27

Redis數據庫命令

2020-08-13 09:55:37

Stream代碼Java

2020-09-16 06:09:43

開源工具PulpLinux

2022-07-18 07:12:33

開源Linux

2024-03-07 07:47:04

代碼塊Monitor

2024-03-15 15:12:27

關鍵字底層代碼

2023-05-10 08:29:28

Spring配置原理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清视频在线播放 | 激情毛片 | 超碰免费在| 国产成人高清在线观看 | 黑人精品xxx一区一二区 | 日韩欧美精品一区 | 久久高清| 国产高清免费 | 99久久日韩精品免费热麻豆美女 | 欧美三级三级三级爽爽爽 | 精品熟人一区二区三区四区 | 精品久久久久久亚洲精品 | 一区二区国产在线 | www精品美女久久久tv | 亚洲欧美v | 性色av一区二区三区 | 国产精品久久久久久久久免费高清 | 热久色 | 欧美日韩一区二区在线播放 | 亚洲成人天堂 | 亚洲精品美女视频 | 日本视频在线播放 | 欧美h视频| 第四色播日韩第一页 | 六月色婷 | 日韩美女在线看免费观看 | 超碰地址| 91欧美精品成人综合在线观看 | 波波电影院一区二区三区 | 成人激情视频在线观看 | www.蜜桃av| 国产成人免费视频网站高清观看视频 | 久久久一区二区 | 久久精品国产亚洲一区二区三区 | 青草久久免费视频 | 毛片一区二区三区 | 亚洲伊人久久综合 | 韩国av一区二区 | 天天人人精品 | 欧美一a一片一级一片 | 日韩在线视频一区 |