首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 線程同步機制全解析:同步代碼塊、同步方法與 Lock 鎖實戰對比

     編輯:Java 綜合教學

Java 線程同步機制全解析:同步代碼塊、同步方法與 Lock 鎖實戰對比

Java 線程同步的核心邏輯遵循:**加鎖 → 修改共享資源 → 釋放鎖**。本文通過三種主流方式實現多線程對共享變數 i 的安全遞增輸出,深度對比其原理與適用場景。

1. 同步代碼塊 (synchronized block)

顯式指定鎖物件 (通常為共享資源本身),粒度精細,靈活度高。

public class SyncBlock {
    static class DataWrap { int i; }

    static class SyncBlockThread extends Thread {
        private final DataWrap data;
        public SyncBlockThread(DataWrap data) { this.data = data; }

        @Override
        public void run() {
            for (int k = 0; k < 10; k++) {
                synchronized (data) { // 鎖住共享資源 data
                    data.i++;
                    try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
                    System.out.println(getName() + " " + data.i);
                }
            }
        }
    }

    public static void main(String[] args) {
        DataWrap shared = new DataWrap();
        new SyncBlockThread(shared).start();
        new SyncBlockThread(shared).start();
        new SyncBlockThread(shared).start();
    }
}

關鍵點:鎖物件需為共享可見物件;sleep()/yield() 不會釋放鎖;同步塊外代碼並發執行,提高吞吐量。

2. 同步方法 (synchronized method)

隱式鎖定 this (實例方法) 或 Class 物件 (靜態方法)。簡潔但粒度較粗,調用該物件任何同步方法均需排隊。

public class SyncMethod {
    static class DataWrap {
        int i;
        public synchronized void valueGrow() { // 鎖住 this (dataWrap 實例)
            i++;
            try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
    // Thread 類與 main 方法結構同 SyncBlock,調用 dataWrap.valueGrow()
}

注意:一線程持有物件鎖時,其他線程調用該物件任意同步方法均阻塞,甚至包括無關業務邏輯的方法。

3. 顯式 Lock 鎖 (java.util.concurrent.locks.Lock)

提供比 synchronized 更豐富的功能:可中斷獲取鎖、超時獲取、公平鎖/非公平鎖、條件變量 (Condition) 等。必須在 finally 中釋放鎖,防止死鎖。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SyncLock {
    static class DataWrap {
        final Lock lock = new ReentrantLock(); // 可重入鎖
        int i;
        public void valueGrow() {
            lock.lock(); // 加鎖
            try {
                i++;
                try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println(Thread.currentThread().getName() + " " + i);
            } finally {
                lock.unlock(); // 關鍵:確保釋放鎖
            }
        }
    }
    // Thread 類與 main 方法結構同上
}

三種方式對比總結

維度同步代碼塊同步方法Lock 鎖
鎖物件任意物件 (顯式指定)this / Class 物件 (隱式)Lock 實例 (顯式管理)
釋放機制塊結束自動釋放方法返回自動釋放手動 unlock() (需 finally)
靈活性高 (可縮小同步範圍)低 (整個方法同步)最高 (可中斷、超時、公平、多條件)
效能 (低競爭)優優略低 (API 開銷)
效能 (高競爭)良良優 (ReentrantLock 優化較好)
適用場景精細控制同步範圍簡單業務、整個方法需原子性複雜同步邏輯、需高級特性 (讀寫鎖等)

進階鎖類型提示

  • ReentrantReadWriteLock:讀寫分離,讀讀並行,讀寫/寫寫互斥,適合「讀多寫少」場景。
  • StampedLock (JDK 8+):樂觀讀鎖,進一步提升讀效能,但不支持重入。

選擇原則:能用 synchronized 解決優先用 synchronized (JVM 優化成熟、代碼簡潔);需要高級特性 (超時、中斷、公平、多條件) 時引入 Lock。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved