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

Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 上

 更新時(shí)間:2021年09月23日 15:09:05   作者:沒(méi)頭腦遇到不高興  
在并發(fā)編程中存在線程安全問(wèn)題,主要原因有:1.存在共享數(shù)據(jù) 2.多線程共同操作共享數(shù)據(jù)。關(guān)鍵字synchronized可以保證在同一時(shí)刻,只有一個(gè)線程可以執(zhí)行某個(gè)方法或某個(gè)代碼塊,同時(shí)synchronized可以保證一個(gè)線程的變化可見(jiàn)(可見(jiàn)性),即可以代替volatile

一、線程安全問(wèn)題

1、臨界資源

多線程編程中,有可能會(huì)出現(xiàn)多個(gè)線程同時(shí)訪問(wèn)同一個(gè)共享、可變資源的情況,這個(gè)資源我們稱(chēng)之其為臨界資源;這種資源可能是:對(duì)象、變量、文件等。

  1. 共享:資源可以由多個(gè)線程同時(shí)訪問(wèn)
  2. 可變:資源可以在其生命周期內(nèi)被修改

2、線程安全問(wèn)題

當(dāng)多個(gè)線程同時(shí)訪問(wèn)一個(gè)對(duì)象時(shí),如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替執(zhí)行,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作,調(diào)用這個(gè)對(duì)象的行為都可以獲得正確的結(jié)果,那就稱(chēng)這個(gè)對(duì)象是線程安全的,否則就是非線程安全的。

3、如何解決線程安全問(wèn)題

互斥同步(Mutual Exclusion & Synchronization)是一種最常見(jiàn)也是最主要的并發(fā)正確性保障手段。同步是指在多個(gè)線程并發(fā)訪問(wèn)共享數(shù)據(jù)時(shí),保證共享數(shù)據(jù)在同一個(gè)時(shí)刻只被一條(或者是一些,當(dāng)使用信號(hào)量的時(shí)候)線程使用。而互斥是實(shí)現(xiàn)同步的一種手段,臨界區(qū)(Critical Section)、互斥量(Mutex)和信號(hào)量(Semaphore)都是常見(jiàn)的互斥實(shí)現(xiàn)方式。

在Java里面,最基本的互斥同步手段就是synchronized關(guān)鍵字,另外還有從JDK1.5開(kāi)始引入了JUC里面的Lock接口,其中用的比較多的就是ReentrantLock,后面也會(huì)進(jìn)行介紹。

二、synchronized使用介紹

synchronized是JVM內(nèi)置的,是可重入的,其使用方法有三種:加在static修飾的靜態(tài)方法上,加在普通方法上,同步代碼塊三種方式。

  1. 加在靜態(tài)方法上(public synchronized static void test()),鎖的是當(dāng)前類(lèi)的Class對(duì)象
  2. 加在實(shí)例方法上(public synchronized void test()),鎖的是當(dāng)前對(duì)象
  3. synchronized同步代碼塊(synchronized(object) {......}),鎖的是synchronized后面括號(hào)里面的對(duì)象

從上面可以看出synchronized鎖的其實(shí)都是對(duì)象。

三、synchronized實(shí)現(xiàn)原理

1、synchronized底層指令:monitorenter和monitorexit

synchronized是基于JVM內(nèi)置鎖實(shí)現(xiàn),通過(guò)內(nèi)部對(duì)象Object Monitor(監(jiān)視器鎖)實(shí)現(xiàn),基于進(jìn)入與退出Monitor對(duì)象實(shí)現(xiàn)方法與代碼塊同步,監(jiān)視器鎖的實(shí)現(xiàn)依賴(lài)底層操作系統(tǒng)的Mutex lock(互斥鎖)實(shí)現(xiàn),它是一個(gè)重量級(jí)鎖性能較低。當(dāng)然,JVM內(nèi)置鎖在1.5之后版本做了重大的優(yōu)化,如鎖粗化(Lock Coarsening)、鎖消除(Lock Elimination)、輕量級(jí)鎖(Lightweight Locking)、偏向鎖(Biased Locking)、適應(yīng)性自旋(Adaptive Spinning)等技術(shù)來(lái)減少鎖操作的開(kāi)銷(xiāo),內(nèi)置鎖的并發(fā)性能已經(jīng)基本與Lock持平。

注意:只有synchronized鎖升級(jí)為重量級(jí)鎖時(shí)才會(huì)用到Object Monitor(監(jiān)視器鎖)。

synchronized關(guān)鍵字被編譯成字節(jié)碼后會(huì)被翻譯成monitorenter 和monitorexit 兩條指令分別在同步塊邏輯代碼的起始位置與結(jié)束位置。

public class TestSynchronized {
    private Object obj = new Object();
    public void testLock() {
        synchronized (obj) {
            System.out.println("獲取了鎖");
        }
    }
}

我們通過(guò)javap -c TestSynchronized.class將上面代碼的class文件進(jìn)行反匯編,可以看到如下所示:我們看到了monitorenter 和monitorexit 兩條指令,但是monitorexit卻出現(xiàn)了兩次,原因如下:

  • 第一個(gè)monitorexit指令是同步代碼塊正常釋放鎖的一個(gè)標(biāo)志;
  • 如果同步代碼塊中出現(xiàn)Exception或者Error,則會(huì)調(diào)用第二個(gè)monitorexit指令來(lái)保證釋放鎖
public void testLock();
    Code:
       0: aload_0
       1: getfield      #3                  // Field obj:Ljava/lang/Object;
       4: dup
       5: astore_1
       6: monitorenter
       7: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #5                  // String 鑾峰彇浜?jiǎn)閿?
      12: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: aload_1
      16: monitorexit
      17: goto          25
      20: astore_2
      21: aload_1
      22: monitorexit
      23: aload_2
      24: athrow
      25: return
    Exception table:
       from    to  target type
           7    17    20   any
          20    23    20   any

2、Object Monitor(監(jiān)視器鎖)機(jī)制

上面提到了,只有synchronized鎖升級(jí)為重量級(jí)鎖時(shí)才會(huì)用到Object Monitor(監(jiān)視器鎖)。我們看一下Object Monitor的實(shí)現(xiàn)機(jī)制是什么?查看OpenJDK源碼可以看到Object Monitor由C++語(yǔ)言實(shí)現(xiàn),打開(kāi)JDK源碼目錄 “jdk\hotspot\src\share\vm\runtime“可以看到objectMonitor.hpp,這個(gè)就是監(jiān)視器鎖的實(shí)現(xiàn),截取一段代碼如下:

ObjectMonitor() {
	_header       = NULL; //對(duì)象頭
	_count        = 0;	//記錄加鎖次數(shù),鎖重入時(shí)用到
	_waiters      = 0, //當(dāng)前有多少處于wait狀態(tài)的thread
	_recursions   = 0; //記錄鎖的重入次數(shù)
	_object       = NULL;
	_owner        = 0; //指向持有ObjectMonitor對(duì)象的線程
	_WaitSet      = NULL; //處于wait狀態(tài)的線程,會(huì)被加入到_WaitSet
	_WaitSetLock  = 0 ;
	_Responsible  = NULL ;
	_succ         = NULL ;
	_cxq          = NULL ;
	FreeNext      = NULL ;
	_EntryList    = NULL ;//處于等待加鎖block狀態(tài)的線程,會(huì)被加入到該列表
	_SpinFreq     = 0 ;
	_SpinClock    = 0 ;
	OwnerIsThread = 0 ;
	_previous_owner_tid = 0;
}

其中幾個(gè)比較重要的字段:

  • _header 對(duì)象頭,前面說(shuō)過(guò)synchronized鎖升級(jí)為重量級(jí)鎖之后才會(huì)用到objectMonitor,這時(shí)候?qū)ο箢^的Mark word會(huì)有一個(gè)指向重量級(jí)鎖Monitor的指針
  •  _count 線程獲取鎖的次數(shù),每加鎖一次該值加1。
  • _waiters 當(dāng)前有多少處于wait狀態(tài)的thread
  • _recursions 鎖的重入次數(shù) 
  • _owner 指向持有ObjectMonitor對(duì)象的線程地址。 
  • _WaitSet 存放調(diào)用wait方法,而進(jìn)入等待狀態(tài)的線程的隊(duì)列。
  • _EntryList 處于等待加鎖block狀態(tài)的線程,會(huì)被加入到該列表

ObjectMonitor的加鎖解鎖過(guò)程如下圖所示,ObjectMonitor中有兩個(gè)隊(duì)列,_WaitSet 和 _EntryList,用來(lái)保存ObjectWaiter對(duì)象列表(每個(gè)等待鎖的線程都會(huì)被封裝成ObjectWaiter對(duì)象);整個(gè)monitor運(yùn)行的機(jī)制過(guò)程如下:

  • _owner指向持有ObjectMonitor對(duì)象的線程,當(dāng)多個(gè)線程同時(shí)訪問(wèn)一段同步代碼時(shí),首先會(huì)進(jìn)入 _EntryList 集合
  • 當(dāng)線程獲取到對(duì)象的monitor 后進(jìn)入 _Owner 區(qū)域并把monitor中的owner變量設(shè)置為當(dāng)前線程的同時(shí),monitor中的計(jì)數(shù)器count加1,
  • 若已經(jīng)獲取鎖的線程調(diào)用 wait() 方法,將釋放當(dāng)前持有的monitor,owner變量恢復(fù)為null,count自減1,同時(shí)該線程進(jìn)入 WaitSet集合中等待被喚醒。
  • 若當(dāng)前線程執(zhí)行完畢也將釋放monitor(鎖)并復(fù)位變量的值,以便其他線程進(jìn)入獲取monitor(鎖)。

下節(jié)將會(huì)介紹一下synchronized的鎖優(yōu)化和鎖升級(jí)過(guò)程

到此這篇關(guān)于Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 上的文章就介紹到這了,更多相關(guān)Java 并發(fā)編程 Synchronized內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis學(xué)習(xí)筆記之動(dòng)態(tài)SQL揭秘

    Mybatis學(xué)習(xí)筆記之動(dòng)態(tài)SQL揭秘

    這篇文章主要給大家介紹了關(guān)于Mybatis學(xué)習(xí)筆記之動(dòng)態(tài)SQL的相關(guān)資料,小編覺(jué)得挺不錯(cuò)的,對(duì)大家學(xué)習(xí)或者使用Mybatis會(huì)有一定的幫助,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • 基于SpringCloud手寫(xiě)一個(gè)簡(jiǎn)易版Sentinel

    基于SpringCloud手寫(xiě)一個(gè)簡(jiǎn)易版Sentinel

    SpringCloud Alibaba Sentinel是當(dāng)前最為流行一種熔斷降級(jí)框架,簡(jiǎn)單易用的方式可以快速幫助我們實(shí)現(xiàn)服務(wù)的限流和降級(jí),保證服務(wù)的穩(wěn)定性。
    2021-05-05
  • Lucene實(shí)現(xiàn)索引和查詢(xún)的實(shí)例講解

    Lucene實(shí)現(xiàn)索引和查詢(xún)的實(shí)例講解

    下面小編就為大家分享一篇Lucene實(shí)現(xiàn)索引和查詢(xún)的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • Kotlin修飾符lateinit(延遲初始化)案例詳解

    Kotlin修飾符lateinit(延遲初始化)案例詳解

    這篇文章主要介紹了Kotlin修飾符lateinit(延遲初始化)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • Java用棧實(shí)現(xiàn)綜合計(jì)算器

    Java用棧實(shí)現(xiàn)綜合計(jì)算器

    棧(stack)又名堆棧,它是一種運(yùn)算受限的線性表,下面看一下如何在Java中,利用數(shù)組實(shí)現(xiàn)模擬一個(gè)棧,感興趣的朋友跟隨小編一起看看吧
    2022-06-06
  • java 中HashMap、HashSet、TreeMap、TreeSet判斷元素相同的幾種方法比較

    java 中HashMap、HashSet、TreeMap、TreeSet判斷元素相同的幾種方法比較

    這篇文章主要介紹了從源碼的角度淺析HashMap、TreeMap元素的存儲(chǔ)和獲取元素的邏輯;從Map與Set之間的關(guān)系淺析常用的Set中元素的存儲(chǔ)和判斷是否重復(fù)的邏輯,需要的朋友可以參考下
    2017-01-01
  • springboot項(xiàng)目test文件夾下帶main方法的類(lèi)不能運(yùn)行問(wèn)題

    springboot項(xiàng)目test文件夾下帶main方法的類(lèi)不能運(yùn)行問(wèn)題

    這篇文章主要介紹了springboot項(xiàng)目test文件夾下帶main方法的類(lèi)不能運(yùn)行問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Spring Boot 集成Dubbo框架實(shí)例

    Spring Boot 集成Dubbo框架實(shí)例

    本篇文章主要介紹了Spring Boot 集成Dubbo框架實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • Java數(shù)據(jù)類(lèi)型轉(zhuǎn)換實(shí)例解析

    Java數(shù)據(jù)類(lèi)型轉(zhuǎn)換實(shí)例解析

    這篇文章主要介紹了Java數(shù)據(jù)類(lèi)型轉(zhuǎn)換實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Spring Cloud中Eureka開(kāi)啟密碼認(rèn)證的實(shí)例

    Spring Cloud中Eureka開(kāi)啟密碼認(rèn)證的實(shí)例

    這篇文章主要介紹了Spring Cloud中Eureka開(kāi)啟密碼認(rèn)證的實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05

最新評(píng)論

南漳县| 于田县| 娱乐| 武川县| 浑源县| 茶陵县| 高邑县| 昔阳县| 噶尔县| 育儿| 安西县| 南和县| 小金县| 上杭县| 宁国市| 鄢陵县| 漠河县| 沂水县| 银川市| 东城区| 泉州市| 安康市| 泊头市| 张家港市| 辽宁省| 青铜峡市| 奈曼旗| 奇台县| 大石桥市| 全州县| 西林县| 邳州市| 左贡县| 永济市| 天镇县| 宁夏| 金寨县| 洛扎县| 新野县| 英山县| 厦门市|