1. 程式人生 > >物件級別鎖 vs 類級別鎖(Java)

物件級別鎖 vs 類級別鎖(Java)

前言

對於多執行緒(併發)和Spring Boot這兩塊在同步進行學習中,在看到使用synchronized關鍵字使操作同步時,看到和C#中不一樣的東西,所以這裡呢,就深入學習了下,若有錯誤之處,還望指正。

物件級別鎖 vs 類級別鎖

我們知道由於併發會導致執行緒不安全的問題,此時我們手段之一採取執行緒同步,也就是說使得所有併發執行緒在執行中保持同步的過程,當方法宣告為同步時,傳遞到同步塊中的物件稱之為監視器或鎖定物件,如果有另外一個執行緒也在執行該同步方法,那麼該執行緒將被阻塞,直到執行緒釋放該監視器或鎖定物件。我們在類中已定義的方法或塊上使用synchronized關鍵字,同時synchronized關鍵字不能與類定義中的變數或屬性一起使用。

物件級別鎖

所謂的物件級別鎖,也就是針對非靜態方法執行同步塊鎖定,那麼同步塊中的監視器或鎖定物件則是基於物件例項,有如下三種形式

class Test {
    public synchronized void LockMethod() {
    }
}

或者

class Test {
    public  void LockMethod() {
        synchronized(this)
        {
        }
    }
}

或者

class Test {
    private final Object lock = new Object();

    public void LockMethod() {
        synchronized (lock) {
        }
    }
}

類級別鎖

若在同步方法中存在靜態資料,為保持靜態資料執行緒安全,我們則需使用類級別鎖,這意味著,如果在執行時有多個例項的Test,則一次只能在一個例項中的一個執行緒上執行一個執行緒LockMethod(),而所有其他例項將被其他執行緒鎖定。針對類級別鎖,那麼同步塊中監視器或鎖定物件有如下三種形式:

class Test {
    public synchronized static void LockMethod() {
    }
}

class Test {
    public void LockMethod() {
        synchronized (Test.class)
        {
        }
    }
}

class Test {
    private final static Object lock = new Object();

    public void LockMethod() {
        synchronized (lock) {
        }
    }
}

在這裡我主要是看到了上述第二種形式中所使用的鎖定物件,由於java和C#語法大多相似,但是這在C#中找不到可對比的東西,我不明白這到底是什麼個意思,所以就深入看了些,本以為可以直接檢視原始碼,然而並沒有任何反應,看來就是Java中天然存在的了,我去打印發現和獲取例項的類名的結果是一樣的,我們將這種情況翻譯為className.class,這到底是什麼意思呢?為何上述第二種形式就是類級別鎖定從而保證執行緒安全了呢?

System.out.println(Test.class.toString());
System.out.println(new Test().getClass());

於是乎我想到看一下所購買的《深入理解Java虛擬機器》中對於類載入原理的解釋,結果發現:在類載入時機的第一階段也就是載入階段,虛擬機器會完成3件事情,其中最後一件事情則是在記憶體中生成一個對應類的java.lang.Class物件,作為方法區這個類的各種資料的入口。換句話說,每個類在JVM中有且只會有唯一的一個java.lang.Class物件例項,所以我大膽猜測className.class就是獲取java.lang.Class物件唯一例項的引用,如此一來就保證始終只有一個執行緒能夠進入同步塊。

總結

本節我們通過對關鍵字synchronized實現執行緒同步做了詳細瞭解,其實並不難,這裡我想表達的是看到和C#中不一樣的東西,也就是className.class具體是什麼意思,同時在用java實現單例模式中也有這種情況,所以詳細學習了下,也做個備忘錄,可能對大部分學java的童鞋而言確實很簡單,我還是處於初級階段,也是在一步步深入的學習。