如何理解Java中眼花繚亂的各種并發鎖?( 二 )


在 Java 中可以通過構造函數初始化公平鎖 , 如代碼所示:
/*** 創建一個可重入鎖 , * true 表示公平鎖,* false 表示非公平鎖 。* 默認非公平鎖 */Lock lock = new ReentrantLock(true);非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序,有可能后申請的線程比先申請的線程優先獲取鎖,在高并發環境下,有可能造成優先級翻轉 , 或者某個線程一直得不到鎖的饑餓狀態 。

如何理解Java中眼花繚亂的各種并發鎖?

文章插圖
【如何理解Java中眼花繚亂的各種并發鎖?】在 Java 中 synchronized 關鍵字是非公平鎖 , ReentrantLock默認也是非公平鎖,如代碼所示:
/*** 創建一個可重入鎖,true 表示公平鎖,false 表示非公平鎖 。默認非公平鎖*/Lock lock = new ReentrantLock(false);4)一個線程中的多個流程,是否獲取同一把鎖的情況如果一個線程中的多個流程能獲取同一把鎖,就使用可重入鎖,如果線程的多個流程不能獲取通一把鎖 , 就是用不可重入鎖 ??芍厝腈i又稱為遞歸鎖 , 是指同一個線程在外層方法獲取了鎖,在進入內層方法會自動獲取鎖 。
對于Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖 。對于synchronized而言,也是一個可重入鎖 。可重入鎖的一個好處是可一定程度避免死鎖 。以 synchronized 為例,來看這樣一段代碼:
public synchronized void mehtodA() throws Exception{// Do some magic tingsmehtodB();}public synchronized void mehtodB() throws Exception{// Do some magic tings}在這段代碼中 methodA() 調用 methodB(),如果一個線程調用methodA() 已經獲取了鎖再去調用 methodB() 就不需要再次獲取鎖了,這就是可重入鎖的特性 。如果是不可重入鎖的話,mehtodB() 可能不會被當前線程執行 , 可能造成死鎖 。
5)某個線程鎖住同步資源失敗,是否不阻塞的情況如果某個線程鎖住同步資源失敗,但是希望這個線程不阻塞,就可以使用自旋鎖或者自適應自旋鎖 。自旋鎖是指線程在沒有獲得鎖時不是被直接掛起 , 而是執行一個忙循環,這個忙循環就是所謂的自旋 。
如何理解Java中眼花繚亂的各種并發鎖?

文章插圖
自旋鎖的目的是為了減少線程被掛起的幾率,因為線程的掛起和喚醒也都是耗資源的操作 。如果鎖被另一個線程占用的時間比較長,即使自旋了之后當前線程還是會被掛起 , 忙循環就會變成浪費系統資源的操作,反而降低了整體性能 。因此自旋鎖是不適應鎖占用時間長的并發情況的 。在 Java 中,AtomicInteger 類就有自旋的操作,來看這樣一段代碼:
public final int getAndAddInt(Object o, long offset, int delta) {int v;do {v = getIntVolatile(o, offset);} while (!compareAndSwapInt(o, offset, v, v + delta));return v;}循環條件調用compareAndSwapInt()方法 , 被稱為CAS操作,如果失敗就會一直循環獲取當前 value 值然后重試,這個過程叫自旋 。在JDK1.6引入了自適應自旋 , 這個就比較智能了,自旋時間不再固定 , 由前一次在同一個鎖上的自旋時間以及鎖的擁有者的狀態來決定 。如果虛擬機認為這次自旋也很有可能再次成功那就會次序較多的時間,如果自旋很少成功,那以后可能就直接省略掉自旋過程,避免浪費處理器資源 。
6)線程競爭同步資源時 , 細節流程是否發生變化的情況JDK1.6 為了提升性能減少獲得鎖和釋放鎖所帶來的消耗,引入了4種鎖的狀態:無鎖、偏向鎖、輕量級鎖和重量級鎖,它會隨著多線程的競爭情況逐漸升級,但不能降級 。
如何理解Java中眼花繚亂的各種并發鎖?

文章插圖
如果多個線程中,只有一個線程能修改資源成功,其他資源只是重試 , 不鎖住資源,稱為無鎖狀態,其實就是樂觀鎖 。第一個線程訪問加鎖的資源自動獲取鎖 , 不存在多線程競爭的情況,資源偏向于第一個訪問鎖的線程,每次訪問線程不需要重復獲取鎖,這種狀態稱為偏向鎖 。偏向鎖的實現是通過控制對象Mark Word的標志位來實現的 , 如果當前是可偏向狀態,需要進一步判斷對象頭存儲的線程 ID 是否與當前線程 ID 一致,如果一致直接進入 。當線程競爭變得比較激烈時 , 偏向鎖就會升級為輕量級鎖,輕量級鎖認為雖然競爭是存在的,但是理想情況下競爭的程度很低,通過自旋方式等待上一個線程釋放鎖 。但如果線程并發進一步加劇,線程的自旋超過了一定次數,或者一個線程持有鎖,一個線程在自旋,又來了第三個線程訪問的時候,輕量級鎖就會膨脹為重量級鎖,重量級鎖會使除了當時擁有鎖的線程以外的所有線程都阻塞 。升級到重量級鎖其實就是互斥鎖了,一個線程拿到鎖,其余線程都會處于阻塞等待狀態 。在 Java 中,synchronized 關鍵字內部實現原理就是這樣一個鎖升級的過程 。

推薦閱讀