談談java中的synchronized關鍵字


 

1.synchronized的3種用法

 

public class Client {
    public static void main(String[] args) {
        testSynchronized();
    }

    private static void testSynchronized() {
        new Foo().sayHello();
    }
    static class Foo {
    //修飾代碼塊
    void sayHello() {
        synchronized (this) {
            System.out.println("hello");
        }
    }
    //修飾示例方法
    synchronized void sayGood(){
        System.out.println("good");
    }
    //修飾靜態方法
    static synchronized void sayHi(){
        System.out.println("hi");
    }
  } 
}

  

(1)修飾實例方法,作用於當前對象實例加鎖,進入同步代碼前要獲得當前對象實例的鎖
(2)修飾靜態方法,作用於當前類對象加鎖,進入同步代碼前要獲得當前類對象的鎖 。也就是給當前類加鎖,會作
用於類的所有對象實例,因為靜態成員不屬於任何一個實例對象,是類成員( static 表明這是該類的一個靜態
資源,不管new了多少個對象,只有一份,所以對該類的所有對象都加了鎖)。所以如果一個線程A調用一個實
例對象的非靜態 synchronized 方法,而線程B需要調用這個實例對象所屬類的靜態 synchronized 方法,是允
許的,不會發生互斥現象,因為訪問靜態 synchronized 方法占用的鎖是當前類的鎖,而訪問非靜態
synchronized 方法占用的鎖是當前實例對象鎖。
(3)修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象的鎖。 和 synchronized 方
法一樣,synchronized(this)代碼塊也是鎖定當前對象的。synchronized 關鍵字加到 static 靜態方法和
synchronized(class)代碼塊上都是是給 Class 類上鎖。這里再提一下:synchronized關鍵字加到非 static 靜態
方法上是給對象實例上鎖。

2.synchronized的底層原理

synchronized 關鍵字底層原理屬於 JVM 層面。通過 JDK 自帶的 javap 命令查看 Foo類的相關字節碼信息: javap  -v Client$Foo.class

 

synchronized 同步語句塊的實現使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同
步代碼塊的開始位置,monitorexit 指令則指明同步代碼塊的結束位置。 當執行 monitorenter 指令時,線程試圖
獲取鎖也就是獲取 monitor(monitor對象存在於每個Java對象的對象頭中,synchronized 鎖便是通過這種方式獲取
鎖的,也是為什么Java中任意對象可以作為鎖的原因) 的持有權.當計數器為0則可以成功獲取,獲取后將鎖計數器設
為1也就是加1。相應的在執行 monitorexit 指令后,將鎖計數器設為0,表明鎖被釋放。如果獲取對象鎖失敗,那當
前線程就要阻塞等待,直到鎖被另外一個線程釋放為止。

synchronized 修飾方法的的情況

 

synchronized 修飾的方法並沒有 monitorenter 指令和 monitorexit 指令,取得代之的確實是
ACC_SYNCHRONIZED 標識,該標識指明了該方法是一個同步方法,JVM 通過該 ACC_SYNCHRONIZED 訪問標志來
辨別一個方法是否聲明為同步方法,從而執行相應的同步調用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM