溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java關鍵字synchronized原理與鎖的狀態實例分析

發布時間:2022-08-10 13:56:53 來源:億速云 閱讀:209 作者:iii 欄目:開發技術

Java關鍵字synchronized原理與鎖的狀態實例分析

引言

在多線程編程中,線程安全是一個非常重要的問題。Java提供了多種機制來保證線程安全,其中synchronized關鍵字是最常用的一種。synchronized關鍵字可以用于方法或代碼塊,確保同一時間只有一個線程可以執行被synchronized修飾的代碼。本文將深入探討synchronized關鍵字的原理,并結合實例分析鎖的狀態。

1. synchronized關鍵字的基本用法

synchronized關鍵字可以用于修飾方法或代碼塊,確保同一時間只有一個線程可以執行被synchronized修飾的代碼。

1.1 修飾實例方法

synchronized修飾實例方法時,鎖對象是當前實例對象(this)。

public class SynchronizedExample {
    public synchronized void method() {
        // 同步代碼塊
    }
}

1.2 修飾靜態方法

synchronized修飾靜態方法時,鎖對象是當前類的Class對象。

public class SynchronizedExample {
    public static synchronized void staticMethod() {
        // 同步代碼塊
    }
}

1.3 修飾代碼塊

synchronized還可以用于修飾代碼塊,鎖對象可以是任意對象。

public class SynchronizedExample {
    private final Object lock = new Object();

    public void method() {
        synchronized (lock) {
            // 同步代碼塊
        }
    }
}

2. synchronized關鍵字的原理

synchronized關鍵字的實現依賴于Java對象頭中的Mark WordMonitor機制。

2.1 對象頭與Mark Word

在Java中,每個對象都有一個對象頭,對象頭包含兩部分信息:Mark WordKlass Pointer。Mark Word用于存儲對象的哈希碼、GC分代年齡、鎖狀態等信息。

在32位JVM中,Mark Word的結構如下:

鎖狀態 25bit 4bit 1bit (偏向鎖) 2bit (鎖標志位)
無鎖 對象的哈希碼 對象分代年齡 0 01
偏向鎖 線程ID Epoch 1 01
輕量級鎖 指向棧中鎖記錄的指針 00
重量級鎖 指向互斥量(Monitor)的指針 10
GC標記 11

2.2 Monitor機制

Monitor是Java中實現同步的基礎。每個Java對象都與一個Monitor相關聯,Monitor可以理解為一個鎖對象。當一個線程進入synchronized代碼塊時,它會嘗試獲取對象的Monitor,如果成功獲取,則進入同步代碼塊執行;如果失敗,則進入阻塞狀態,直到其他線程釋放Monitor。

Monitor的實現依賴于操作系統的互斥量(Mutex)和條件變量(Condition Variable)。在JVM中,Monitor的實現通常是通過ObjectMonitor類來完成的。

3. 鎖的狀態

Java中的鎖有四種狀態:無鎖、偏向鎖、輕量級鎖和重量級鎖。鎖的狀態會根據競爭情況動態升級。

3.1 無鎖

無鎖狀態是指對象沒有被任何線程持有鎖。在無鎖狀態下,Mark Word中存儲的是對象的哈希碼和分代年齡。

3.2 偏向鎖

偏向鎖是為了在沒有競爭的情況下減少同步開銷而引入的。當一個線程第一次獲取鎖時,JVM會將鎖狀態設置為偏向鎖,并將Mark Word中的線程ID設置為當前線程的ID。之后,如果同一個線程再次請求鎖,JVM會直接允許其進入同步代碼塊,而不需要進行任何同步操作。

偏向鎖的優點是減少了無競爭情況下的同步開銷,但在有競爭的情況下,偏向鎖會升級為輕量級鎖。

3.3 輕量級鎖

輕量級鎖是通過CAS(Compare-And-Swap)操作來實現的。當一個線程嘗試獲取鎖時,JVM會嘗試將Mark Word中的指針替換為指向當前線程棧中鎖記錄的指針。如果替換成功,則獲取鎖成功;如果失敗,則說明有其他線程競爭鎖,此時鎖會升級為重量級鎖。

輕量級鎖的優點是減少了線程阻塞的開銷,但在高競爭的情況下,輕量級鎖會頻繁升級為重量級鎖,導致性能下降。

3.4 重量級鎖

重量級鎖是通過操作系統的互斥量(Mutex)來實現的。當一個線程獲取重量級鎖時,如果鎖已經被其他線程持有,則該線程會進入阻塞狀態,直到鎖被釋放。

重量級鎖的優點是適用于高競爭的情況,但缺點是線程阻塞和喚醒的開銷較大。

4. 鎖的狀態轉換

鎖的狀態會根據競爭情況動態升級,但不會降級。鎖的狀態轉換過程如下:

  1. 無鎖 -> 偏向鎖:當一個線程第一次獲取鎖時,JVM會將鎖狀態設置為偏向鎖。
  2. 偏向鎖 -> 輕量級鎖:當有另一個線程嘗試獲取鎖時,偏向鎖會升級為輕量級鎖。
  3. 輕量級鎖 -> 重量級鎖:當輕量級鎖的CAS操作失敗時,鎖會升級為重量級鎖。

5. 實例分析

下面通過一個實例來分析鎖的狀態轉換過程。

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

    public static void main(String[] args) throws InterruptedException {
        // 線程1獲取鎖
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 1 holds the lock");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 線程2獲取鎖
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2 holds the lock");
            }
        });

        thread1.start();
        Thread.sleep(100); // 確保線程1先獲取鎖
        thread2.start();

        thread1.join();
        thread2.join();
    }
}

在這個例子中,thread1首先獲取鎖并進入同步代碼塊,thread2隨后嘗試獲取鎖。由于thread1持有鎖,thread2會進入阻塞狀態。此時,鎖的狀態會從無鎖升級為偏向鎖,再升級為輕量級鎖,最后升級為重量級鎖。

6. 總結

synchronized關鍵字是Java中實現線程同步的重要機制。通過synchronized關鍵字,可以確保同一時間只有一個線程可以執行被synchronized修飾的代碼。synchronized關鍵字的實現依賴于Java對象頭中的Mark WordMonitor機制。鎖的狀態會根據競爭情況動態升級,從無鎖到偏向鎖,再到輕量級鎖,最后到重量級鎖。

在實際開發中,理解synchronized關鍵字的原理和鎖的狀態轉換過程,有助于我們更好地編寫高效、線程安全的代碼。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女