中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java?Synchronized是什么

發布時間:2023-05-06 11:00:55 來源:億速云 閱讀:111 作者:zzz 欄目:開發技術

本篇內容介紹了“Java Synchronized是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Synchronized是什么

各位Java讀者,對于synchronized關鍵字并不陌生,在各種中間件源碼或者JDK源碼中都能看到,對于不熟悉synchronized的讀者只知道在多線程中需要使用到synchronized關鍵字,知道synchronized能夠保證線程安全。

  • 稱之為:互斥鎖(同時只能一個線程執行,其他的線程將會等待)

  • 又稱之為:悲觀鎖(同時只能一個線程執行,其他的線程將會等待)

  • JVM虛擬機幫你實現,開發者只需要使用synchronized關鍵字即可。

  • 使用時需要用一個對象當鎖的互斥量

  • 能夠保證一段代碼(臨界區)的原子性+可見性。

從字節碼層面解析Synchronized關鍵字

從案例入手,最合適不過。

class Demo1{
    // 互斥對象
    static Object object = new Object();
    // 競爭條件
    static int cout = 0;
    public static void main(String[] args) {
        // 互斥
        synchronized(object){
            // 以下是臨界區
            cout++;
            System.out.println("synchronized");
        }
    }
}

僅僅從Java代碼,我們并不能看出啥東西,而Java程序編譯后是字節碼文件,所以我們解析一遍字節碼

Constant pool:
   #1 = Methodref          #7.#26         // java/lang/Object."<init>":()V
   #2 = Fieldref           #8.#27         // Demo1.object:Ljava/lang/Object;
   #3 = Fieldref           #8.#28         // Demo1.cout:I
   #4 = Fieldref           #29.#30        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = String             #31            // synchronized
   #6 = Methodref          #32.#33        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #7 = Class              #34            // java/lang/Object
   #8 = Class              #35            // Demo1
   #9 = Utf8               object
  #10 = Utf8               Ljava/lang/Object;
  #11 = Utf8               cout
  #12 = Utf8               I
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               StackMapTable
  #20 = Class              #36            // "[Ljava/lang/String;"
  #21 = Class              #34            // java/lang/Object
  #22 = Class              #37            // java/lang/Throwable
  #23 = Utf8               <clinit>
  #24 = Utf8               SourceFile
  #25 = Utf8               Demo1.java
  #26 = NameAndType        #13:#14        // "<init>":()V
  #27 = NameAndType        #9:#10         // object:Ljava/lang/Object;
  #28 = NameAndType        #11:#12        // cout:I
  #29 = Class              #38            // java/lang/System
  #30 = NameAndType        #39:#40        // out:Ljava/io/PrintStream;
  #31 = Utf8               synchronized
  #32 = Class              #41            // java/io/PrintStream
  #33 = NameAndType        #42:#43        // println:(Ljava/lang/String;)V
  #34 = Utf8               java/lang/Object
  #35 = Utf8               Demo1
  #36 = Utf8               [Ljava/lang/String;
  #37 = Utf8               java/lang/Throwable
  #38 = Utf8               java/lang/System
  #39 = Utf8               out
  #40 = Utf8               Ljava/io/PrintStream;
  #41 = Utf8               java/io/PrintStream
  #42 = Utf8               println
  #43 = Utf8               (Ljava/lang/String;)V
         0: getstatic     #2        // 從2號常量池中拿到靜態變量,壓入到操作數棧中                  
         3: dup                     // 把操作數棧棧頂的對象賦值一份
         4: astore_1                // 將操作數棧的數據保存到1號局部變量表中,給釋放鎖使用
         5: monitorenter            // 互斥鎖開啟,也是synchronized的字節碼層面實現
         6: getstatic     #3        // 從2號常量池中拿到靜態變量,壓入到操作數棧中
         9: iconst_1                // 將常量1壓入到操作數棧中
        10: iadd                    // 消耗兩個操作數棧的數據,相加,然后壓入棧頂
        11: putstatic     #3        // 將操作數棧棧頂的變量賦值給3號常量池
        14: getstatic     #4        // 將4號常量池的對象壓入操作數棧
        17: ldc           #5        // 解析5號常量池的符號,拿到字符串常量"synchronized"     
        19: invokevirtual #6        // 執行println函數,消耗2個操作數棧
        22: aload_1                 // 將1號局部變量表的數據壓入操作數棧
        23: monitorexit             // 互斥鎖的結束,也是synchronized的字節碼層面實現
        24: goto          32        // 跳轉到32行。
        27: astore_2                // 可能存在異常,但是要需要釋放鎖,所以把異常對象放入2號局部變量表
        28: aload_1                 // 把1號局部變量表數據壓入操作數棧的棧頂,供monitorexit指令使用
        29: monitorexit             // 可能存在異常,但是要需要釋放鎖,不然死鎖了。
        30: aload_2                 // 把異常對象從2號局部變量表中壓入操作數棧的棧頂
        31: athrow                  // 存在異常拋出
        32: return                  // 函數返回

以上是字節碼全解,其實很簡單,最終Synchronized關鍵字解析成字節為monitorenter和monitorexit字節碼指令,然后每次執行這2個字節碼指令前,把互斥對象壓入操作數棧供給monitorenter和monitorexit字節碼指令使用。

所以下一篇就是去Hotspot源碼中解析monitorenter和monitorexit字節碼指令的詳細流程。

Synchronized與ReentrantLock的區別

這是一道很常見的面試題,面試被問到的頻率非常高

相似點:

都是互斥鎖的實現

不同點:

  • Synchronized基于JVM內部實現,ReentrantLock基于Java層面實現(但是ReentrantLock核心代碼還是調用C++代碼)。

  • Synchronized在1.6以后經過優化,存在幾個不同級別的鎖,根據線程競爭的力度提升鎖的力度(俗稱鎖升級),更多的適合場景,而ReentrantLock在鎖力度選擇上略顯死板。

  • ReentrantLock雖然在鎖力度選擇上略顯死板,但是可以選擇公平和非公平,而Synchronized只能是非公平鎖

  • ReentrantLock的條件等待隊列,可創建多個,高定制化。而Synchronized底層只有一個隊列。

  • ReentrantLock需要用戶手動開啟鎖,手動釋放鎖。而Synchronized關鍵字底層通過字節碼自動實現

“Java Synchronized是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

沾化县| 舟曲县| 定远县| 东光县| 香港| 平泉县| 家居| 仲巴县| 信阳市| 锡林郭勒盟| 郸城县| 景东| 宁波市| 克拉玛依市| 临清市| 元江| 芮城县| 盐源县| 临城县| 望奎县| 白山市| 肇东市| 桃园市| 平安县| 永昌县| 晋城| 石景山区| 广汉市| 丹棱县| 丽水市| 玛纳斯县| 营山县| 清丰县| 彰化市| 随州市| 原平市| 贵定县| 牙克石市| 札达县| 砀山县| 罗江县|