Java對象級別鎖 vs 類級別鎖

前言

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

對象級別鎖 vs 類級別鎖

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

對象級別鎖

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

<code>class Test {
public synchronized void LockMethod() {
}
}/<code>

或者

<code>class Test {
public void LockMethod() {
synchronized(this)
{
}
}
}/<code>

或者

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

public void LockMethod() {
synchronized (lock) {
}
}
}/<code>

類級別鎖

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

<code>class Test {
public synchronized static void LockMethod() {
}
}/<code>

<code>class Test {
public void LockMethod() {
synchronized (Test.class)
{
}
}
}/<code>

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

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

}
}/<code>

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

<code>System.out.println(Test.class.toString());
System.out.println(new Test().getClass());/<code>
Java對象級別鎖 vs 類級別鎖

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

總結

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


分享到:


相關文章: