synchronized(修飾方法和代碼塊)

synchronized(修飾方法和代碼塊)

1. 含義

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

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

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


2. 用法

synchronized 包括三種用法:jvm

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

2.1 修飾實例方法

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

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

2.2 修飾靜態方法

當 synchronized 做用於靜態方法時,其鎖就是當前類的 class 對象鎖。因爲靜態成員不專屬於任何一個實例對象,是類成員,所以經過 class 對象鎖能夠控制靜態成員的併發操做。須要注意的是若是一個線程 A 調用一個實例對象的非 static synchronized 方法,而線程 B 須要調用這個實例對象所屬類的靜態 synchronized 方法,是容許的,不會發生互斥現象,由於訪問靜態 synchronized 方法佔用的鎖是當前類的 class 對象,而訪問非靜態 synchronized 方法佔用的鎖是當前實例對象鎖,兩者的鎖並不同,因此不衝突。this

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

2.3 修飾代碼塊

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

咱們可使用以下幾種對象來做爲鎖的對象:線程

成員鎖

鎖的對象是變量code

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. 參考

相關文章
相關標籤/搜索