synchronized(修飾方法和代碼塊)


synchronized(修飾方法和代碼塊)

1. 含義

  • synchronized 是同步鎖,用來實現互斥同步。

  • 在 Java 中,關鍵字 synchronized 可以保證在同一個時刻,只有一個線程可以執行某個方法或者某個代碼塊(主要是對方法或者代碼塊中存在共享數據的操作)。

  • synchronized 還可以保證一個線程的變化(主要是共享數據的變化)被其他線程所看到(保證可見性,完全可以替代 volatile 功能,但是 volatile 更輕量,還是要分場景使用)。


2. 用法

synchronized 包括三種用法:

  • 修飾實例方法
  • 修飾靜態方法
  • 修飾代碼塊

2.1 修飾實例方法

所謂的實例對象鎖就是用 synchronized 修飾實例對象中的實例方法,注意是實例方法不包括靜態方法,如下:

public synchronized void increase() {
    i++;
}

2.2 修飾靜態方法

當 synchronized 作用於靜態方法時,其鎖就是當前類的 class 對象鎖。由於靜態成員不專屬於任何一個實例對象,是類成員,因此通過 class 對象鎖可以控制靜態成員的並發操作。需要注意的是如果一個線程 A 調用一個實例對象的非 static synchronized 方法,而線程 B 需要調用這個實例對象所屬類的靜態 synchronized 方法,是允許的,不會發生互斥現象,因為訪問靜態 synchronized 方法占用的鎖是當前類的 class 對象,而訪問非靜態 synchronized 方法占用的鎖是當前實例對象鎖,二者的鎖並不一樣,所以不沖突。

public static synchronized void increase() {
    i++;
}

2.3 修飾代碼塊

在某些情況下,我們編寫的方法體可能比較大,同時存在一些比較耗時的操作,而需要同步的代碼又只有一小部分,如果直接對整個方法進行同步操作,可能會得不償失,此時我們可以使用同步代碼塊的方法對需要同步的代碼進行包裹,這樣就無需對整個方法進行同步操作了。

我們可以使用如下幾種對象來作為鎖的對象:

成員鎖

鎖的對象是變量

public Object synMethod(Object a1) {
    synchronized(a1) {
        // 操作
    }
}
實例對象鎖

this 代表當前實例

synchronized(this) {
    for (int j = 0; j < 100; j++) {
		i++;
    }
}
當前類的 class 對象鎖
synchronized(AccountingSync.class) {
    for (int j = 0; j < 100; j++) {
        i++;
    }
}

3. 什么是可重入鎖

含義

所謂可重入鎖,指的是以線程為單位,當一個線程獲取對象鎖之后,這個線程可以再次獲取本對象上的鎖,而其他的線程是不可以的。(同一個加鎖線程自己調用自己不會發生死鎖情況)

意義

防止死鎖。

實現原理

通過為每個鎖關聯一個請求計數和一個占有它的線程。當計數為 0 時,認為鎖是未被占有的。線程請求一個未被占有的鎖時,jvm 將記錄鎖的占有者,並且將請求計數器置為 1 。如果同一個線程再次請求這個鎖,計數將遞增;每次占用線程退出同步塊,計數器值將遞減。直到計數器為0,鎖被釋放。

應用

synchronized 和 ReentrantLock 都是可重入鎖。

ReentrantLock 表現為 API 層面的互斥鎖(lock() 和 unlock() 方法配合 try/finally 語句塊來完成),synchronized 表現為原生語法層面的互斥鎖。


4. 互斥同步的缺點

互斥同步最主要的問題就是進行線程阻塞和喚醒所帶來的性能問題,因此這種同步也被稱為阻塞同步。而且加鎖方式屬於悲觀鎖(不管操作是否成功都加鎖)。


5. 參考


免責聲明!

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



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