天天看點

Java 使用 synchronized 實作内置鎖

文章目錄

    • 1. 對象鎖
      • 1.1. 同步方法
      • 1.2. 同步代碼塊(目前類對象鎖)
      • 1.3. 同步代碼塊(傳入類對象鎖)
    • 2. 類鎖
      • 2.1. 同步靜态方法
      • 2.2. 同步代碼塊(目前類class鎖)

多個程序或線程同時(或着說在同一段時間内)通路同一資源會産生并發(線程安全)問題。解決并發問題可以用鎖。單機情況下可以直接使用

synchronized

關鍵字實作的内置鎖。

每個

Java

對象都可以用做一個實作同步的鎖,這些鎖稱為内置鎖。線程進入同步代碼塊或方法的時候會自動獲得該鎖,在退出同步代碼塊或方法時會釋放該鎖。獲得内置鎖的唯一途徑就是進入這個鎖保護的同步代碼塊或方法。

Java

内置鎖是一個互斥鎖,這就意味着最多隻有一個線程能夠獲得該鎖,當線程

A

嘗試去獲得線程

B

持有的内置鎖時,線程

A

必須等待或者阻塞,直到線程

B

釋放這個鎖,如果線程

B

不釋放這個鎖,那麼線程

A

将永遠等待下去。

Java

的内置鎖基本上可以分為對象鎖和類鎖,對象鎖是用于對象執行個體方法或者對象執行個體上的,類鎖是用于類的靜态方法或者類的

class

對象上的。我們知道,一個類的執行個體對象可以有很多個,但是每個類隻有一個

class

對象,是以不同對象執行個體的對象鎖是互不幹擾的,但是每個類隻有一個類鎖。有一點必須注意的是,其實類鎖隻是一個概念上的東西,并不是真實存在的,它隻是用來幫助我們了解鎖定執行個體方法和靜态方法的差別的。

synchronized

隻是一個内置鎖的加鎖機制,當某個方法加上

synchronized

關鍵字後,就表明要獲得該内置鎖才能執行,并不能阻止其他線程通路不需要獲得該内置鎖的方法。

1. 對象鎖

1.1. 同步方法

同步方法,是對該對象加鎖,其他線程将無法通路需要擷取該對象鎖的方法和代碼塊。

public class Test{
    
    public synchronized void print(){    
        System.out.println("hello world!");
    }
    
}
           

上面代碼表示通路

print()

方法需要擷取

Test

執行個體對象的鎖。

1.2. 同步代碼塊(目前類對象鎖)

同步代碼塊,這種寫法也是鎖住該類的執行個體對象,和

1.1.

效果一樣,其他線程将無法通路需要擷取該對象鎖的方法和代碼塊。

public class Test{
    
    public void print(){    
        synchronized(this){
            System.out.println("hello world!");
        }
    }
    
}
           

上面代碼表示通路

print()

方法中的代碼塊需要擷取

Test

執行個體對象的鎖。

1.3. 同步代碼塊(傳入類對象鎖)

同步代碼塊,這種寫法鎖住傳入的對象,不影響需要擷取目前類對象鎖的方法和代碼塊的通路。

public class Test{
    
    private byte[] lock = new byte[0];
    
    public void print(){    
        synchronized(lock){
            System.out.println("hello world!");
        }
    }
    
    public synchronized void print1(){
        System.out.println("123456");
    }
    
}
           

執行

print()

方法裡面的同步代碼塊,會給

byte[]

對象

lock

加鎖,注意不是給

Test

的對象加鎖,也就是說

Test

對象的其它

synchronized

方法和代碼塊不會因為

print()

而被鎖。

print1()

方法可以正常通路。

2. 類鎖

類鎖修飾方法和代碼塊的效果和對象鎖是一樣的,因為類鎖隻是一個抽象出來的概念,類鎖和對象鎖是互不幹擾的。同樣,線程獲得對象鎖的同時,也可以獲得該類鎖,即同時獲得兩個鎖,這是允許的。

2.1. 同步靜态方法

因為靜态方法是所有對象執行個體共用的,對應着

synchronized

修飾的靜态方法的鎖也是唯一的,是以抽象出來個類鎖。其他線程将無法通路需要擷取該類鎖的方法和代碼塊。

public class Test{
    
    public synchronized static void print(){    
        System.out.println("hello world!");
    }
    
}
           

2.2. 同步代碼塊(目前類class鎖)

這種寫法,直接鎖定目前類的

class

對象,因為每個類隻有一個

class

對象,和

2.1.

效果一樣。其他線程将無法通路需要擷取該類鎖的方法和代碼塊。

public class Test{
    
    public void print(){    
        synchronized(Test.class){
            System.out.println("hello world!");
        }
    }
    
}