中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

Java并發編程之Lock鎖機(ji)制深(shen)度解析:從使用到源碼實現

1. 鎖的基本概念:從現實世界到代碼世界

1.1 鎖的演進:synchronized → Lock

想象一下健身房儲物柜的使用場景:

  • synchronized:像固定密碼鎖 - 簡單易用但功能有限
  • Lock接口:像智能電子鎖 - 功能豐富且靈活可控
// synchronized - 固定密碼鎖
public synchronized void oldMethod() {
    // 自動上鎖和解鎖
    // 但無法中斷、無法超時、無法嘗試獲取
}

// Lock - 智能電子鎖  
public void newMethod() {
    Lock lock = new ReentrantLock();
    lock.lock();  // 手動開鎖
    try {
        // 臨界區代碼
    } finally {
        lock.unlock();  // 手動關鎖
    }
}

1.2 Lock接口的核心優勢

特性 synchronized Lock
中斷響應 ? ?
超時控制 ? ?
嘗試獲取 ? ?
公平性 ? ?
條件隊列 單個 多個

2. AQS:并發世界的交通指揮中心

2.1 AQS的核心設計思想

AQS(AbstractQueuedSynchronizer)就像高速公路收費站系統

  • state狀態:當前可通行的車道數量
  • 同步隊列:等待通行的車輛排隊
  • CAS操作:智能的車輛調度系統
/**
 * AQS同步狀態管理示例
 */
public class AQSCoreConcept {
    // state字段的三種典型用法:
    
    // 1. 互斥鎖:state = 0(未鎖定) 或 1(已鎖定)
    // 2. 重入鎖:state = 重入次數  
    // 3. 讀寫鎖:高16位 = 讀鎖計數,低16位 = 寫鎖計數
    private volatile int state;
    
    // 三個核心的state操作方法:
    protected final int getState() { return state; }
    protected final void setState(int newState) { state = newState; }
    protected final boolean compareAndSetState(int expect, int update) {
        // CAS原子操作,保證線程安全
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
}

2.2 同步隊列:線程的"等候區"

/**
 * AQS同步隊列結構演示
 */
public class SyncQueueDemo {
    /**
     * 同步隊列節點結構(雙向鏈表):
     * 
     * head (虛擬節點) ? [prev|thread|next|waitStatus] ? [prev|thread|next|waitStatus] ? tail
     * 
     * waitStatus狀態說明:
     * - CANCELLED(1):線程已取消
     * - SIGNAL(-1):后繼線程需要被喚醒  
     * - CONDITION(-2):線程在Condition隊列中
     * - PROPAGATE(-3):共享模式下傳播喚醒
     */
    
    // 獨占模式獲取鎖的典型流程
    public void acquireDemo() {
        Lock lock = new ReentrantLock();
        
        // 底層調用AQS的acquire方法
        lock.lock();  // -> sync.acquire(1);
        
        /**
         * acquire方法執行流程:
         * 1. tryAcquire()嘗試直接獲取鎖
         * 2. 失敗 → addWaiter()加入同步隊列隊尾
         * 3. acquireQueued()在隊列中自旋等待
         * 4. 被前驅節點喚醒后重新嘗試獲取鎖
         */
    }
}

2.3 自定義鎖實戰:基于AQS實現TwinsLock

/**
 * TwinsLock - 同一時刻最多允許兩個線程訪問的共享鎖
 * 設計思路:將AQS的state作為許可證計數器
 */
public class TwinsLock implements Lock {
    private final Sync sync = new Sync(2);
    
    private static final class Sync extends AbstractQueuedSynchronizer {
        Sync(int count) {
            if (count <= 0) throw new IllegalArgumentException("計數必須大于0");
            setState(count);  // 初始化許可證數量
        }
        
        /**
         * 共享模式獲取鎖
         * @return 負數:獲取失敗;0:獲取成功但無剩余;正數:獲取成功且有剩余
         */
        @Override
        public int tryAcquireShared(int reduceCount) {
            for (;;) {  // 自旋避免CAS失敗
                int current = getState();
                int newCount = current - reduceCount;
                
                // 如果新計數<0(無許可證)或CAS設置成功,返回結果
                if (newCount < 0 || compareAndSetState(current, newCount)) {
                    return newCount;
                }
            }
        }
        
        /**
         * 共享模式釋放鎖
         */
        @Override
        public boolean tryReleaseShared(int returnCount) {
            for (;;) {
                int current = getState();
                int newCount = current + returnCount;
                if (compareAndSetState(current, newCount)) {
                    return true;
                }
            }
        }
    }
    
    @Override
    public void lock() {
        sync.acquireShared(1);  // 獲取1個許可證
    }
    
    @Override
    public void unlock() {
        sync.releaseShared(1);  // 釋放1個許可證
    }
    
    // 其他Lock方法實現...
}

/**
 * 測試TwinsLock
 */
public class TwinsLockTest {
    @Test
    public void testTwinsLock() {
        final Lock lock = new TwinsLock();
        
        // 啟動10個線程,但同一時刻只有2個能獲取鎖
        for (int i = 0; i < 10; i++) {
            Thread worker = new Thread(() -> {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 獲取鎖");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                }
            });
            worker.start();
        }
    }
}

3. 重入鎖ReentrantLock:可重復使用的智能鎖

3.1 重入性:一把鑰匙開多把鎖

現實比喻:你(ni)進了(le)自(zi)家(jia)大(da)門(men),還可以用同一(yi)把鑰匙打開臥室門(men)、書房(fang)門(men)。

/**
 * 重入鎖的重入特性演示
 */
public class ReentrantDemo {
    private final ReentrantLock lock = new ReentrantLock();
    
    public void outer() {
        lock.lock();
        try {
            System.out.println("外層方法獲取鎖,重入計數: " + getHoldCount());
            inner();  // 重入:同一個線程再次獲取同一把鎖
        } finally {
            lock.unlock();
        }
    }
    
    public void inner() {
        lock.lock();  // 這里不會阻塞,因為已經是鎖的持有者
        try {
            System.out.println("內層方法獲取鎖,重入計數: " + getHoldCount());
        } finally {
            lock.unlock();
        }
    }
    
    private int getHoldCount() {
        // 返回當前線程持有該鎖的次數
        return lock.getHoldCount();
    }
}

3.2 公平鎖 vs 非公平鎖

公平鎖:像銀行取號排隊 - 先來先服務
非公平鎖:像公交車搶座位 - 誰能搶到誰坐

/**
 * 公平性對比測試
 */
public class FairVsUnfairTest {
    private static Lock fairLock = new ReentrantLock(true);      // 公平鎖
    private static Lock unfairLock = new ReentrantLock(false);   // 非公平鎖
    
    @Test
    public void comparePerformance() {
        // 測試結果通常顯示:
        // - 公平鎖:保證順序,但性能較低
        // - 非公平鎖:可能饑餓,但吞吐量高
        
        testLock("公平鎖", fairLock);
        testLock("非公平鎖", unfairLock);
    }
    
    private void testLock(String type, Lock lock) {
        long start = System.currentTimeMillis();
        
        // 多個線程競爭鎖...
        
        long duration = System.currentTimeMillis() - start;
        System.out.println(type + " 耗時: " + duration + "ms");
    }
}

3.3 重入鎖實現原理

/**
 * 重入鎖核心實現解析
 */
public class ReentrantLockCore {
    /**
     * 非公平鎖獲取邏輯
     */
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        
        if (c == 0) {  // 鎖空閑
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        } else if (current == getExclusiveOwnerThread()) {  // 重入
            int nextc = c + acquires;
            if (nextc < 0) throw new Error("超過最大鎖計數");
            setState(nextc);  // 增加重入計數
            return true;
        }
        return false;
    }
    
    /**
     * 釋放鎖邏輯
     */
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
            
        boolean free = false;
        if (c == 0) {  // 完全釋放
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }
}

4. 讀寫鎖ReentrantReadWriteLock:讀寫分離的高并發鎖

4.1 讀寫鎖的應用場景

現實比喻:圖書館管理規則

  • 讀操作:多人可同時閱讀同一本書
  • 寫操作:修改書籍時需獨占訪問
/**
 * 基于讀寫鎖的緩存實現
 */
public class ReadWriteCache<K, V> {
    private final Map<K, V> cache = new HashMap<>();
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    
    /**
     * 讀操作:共享鎖,允許多個線程同時讀
     */
    public V get(K key) {
        readLock.lock();
        try {
            String value = cache.get(key);
            // 模擬配置讀取的耗時操作
            simulateProcess(1);
            return value;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 批量獲取配置 - 讀鎖支持并發
     */
    public Map<String, String> getConfigs(Set<String> keys) {
        readLock.lock();
        try {
            Map<String, String> result = new HashMap<>();
            for (String key : keys) {
                result.put(key, cache.get(key));
            }
            simulateProcess(keys.size());
            return result;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 更新配置 - 低頻操作,使用寫鎖
     */
    public void updateConfig(String key, String value) {
        writeLock.lock();
        try {
            // 模擬配置更新的耗時操作
            simulateProcess(10);
            cache.put(key, value);
            System.out.println("配置更新: " + key + " = " + value);
        } finally {
            writeLock.unlock();
        }
    }
    
    private void simulateProcess(int milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

4.2 讀寫鎖的狀態設計

/**
 * 讀寫鎖狀態設計的精妙之處
 */
public class ReadWriteStateDesign {
    /**
     * 32位state字段的劃分:
     * 
     * ┌─────────────────┬─────────────────┐
     * │     高16位      │     低16位      │
     * │     讀狀態      │     寫狀態      │
     * │   (讀鎖計數)    │  (寫鎖重入數)   │
     * └─────────────────┴─────────────────┘
     */
    
    // 獲取寫狀態(低16位)
    static int exclusiveCount(int c) { 
        return c & 0x0000FFFF; 
    }
    
    // 獲取讀狀態(高16位)
    static int sharedCount(int c) { 
        return c >>> 16; 
    }
    
    // 讀鎖計數+1
    int newReadState = currentState + (1 << 16);  // 即 + 0x00010000
    
    // 寫鎖計數+1  
    int newWriteState = currentState + 1;
}

4.3 鎖降級:保證數據可見性的重要技術

/**
 * 鎖降級示例:寫鎖 → 讀鎖
 * 目的:保證數據的可見性
 */
public class LockDemotionExample {
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private volatile boolean update = false;
    private Object data;
    
    public void processData() {
        readLock.lock();
        if (!update) {
            // 數據需要更新,必須先釋放讀鎖
            readLock.unlock();
            
            // 獲取寫鎖
            writeLock.lock();
            try {
                // 雙重檢查
                if (!update) {
                    // 準備數據...
                    data = fetchData();
                    update = true;
                }
                // 關鍵步驟:在釋放寫鎖前獲取讀鎖
                readLock.lock();  // 鎖降級開始
            } finally {
                writeLock.unlock();  // 鎖降級完成,現在持有讀鎖
            }
        }
        
        try {
            // 使用數據(仍在讀鎖保護下)
            useData(data);
        } finally {
            readLock.unlock();
        }
    }
    
    // 不支持鎖升級!可能產生死鎖
    public void invalidLockUpgrade() {
        readLock.lock();
        try {
            // 危險操作:嘗試在持有讀鎖時獲取寫鎖
            // 如果其他線程也持有讀鎖,會產生死鎖
            writeLock.lock();  // 可能永遠阻塞!
            try {
                // 修改數據...
            } finally {
                writeLock.unlock();
            }
        } finally {
            readLock.unlock();
        }
    }
    
    private Object fetchData() { return null; }
    private void useData(Object data) {}
}

5. LockSupport:線程的精準遙控器

5.1 LockSupport的核心能力

LockSupport提供線程阻塞和喚醒的原子操作,就像線程的遠程控制器

/**
 * LockSupport基礎使用
 */
public class LockSupportBasic {
    
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            System.out.println("工作線程開始執行");
            System.out.println("工作線程即將被阻塞");
            
            // 阻塞當前線程(停車)
            LockSupport.park();
            
            System.out.println("工作線程被喚醒,繼續執行");
        });
        
        worker.start();
        
        Thread.sleep(2000);  // 主線程等待2秒
        
        System.out.println("主線程準備喚醒工作線程");
        
        // 喚醒指定線程(開車)
        LockSupport.unpark(worker);
        
        System.out.println("主線程已發送喚醒信號");
    }
}

5.2 許可機制:先發后至的靈活性

/**
 * LockSupport的許可機制演示
 * 每個線程有一個許可(最多為1):
 * - unpark:添加一個許可
 * - park:消耗一個許可,沒有許可就阻塞
 */
public class PermitMechanism {
    
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("子線程開始");
            
            try {
                Thread.sleep(1000);  // 確保主線程先調用unpark
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            
            System.out.println("子線程調用park");
            
            // 這里不會阻塞,因為主線程已經給了許可
            LockSupport.park();
            System.out.println("子線程第一次park完成");
            
            // 這次會阻塞,因為許可已經被消耗
            LockSupport.park(); 
            System.out.println("子線程第二次park完成");
        });
        
        thread.start();
        
        // 立即給子線程許可(先發)
        System.out.println("主線程調用unpark");
        LockSupport.unpark(thread);
        
        // 等待后再次喚醒
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("主線程再次調用unpark");
        LockSupport.unpark(thread);
    }
}

5.3 Blocker:線程診斷的"身份證"

/**
 * Blocker的作用:在線程dump中標識等待目標
 */
public class BlockerDemo {
    
    public static void main(String[] args) throws InterruptedException {
        Object blocker = new Object();  // 阻塞對象
        
        Thread withBlocker = new Thread(() -> {
            System.out.println("帶Blocker的線程開始阻塞");
            // 推薦:使用帶blocker的park方法
            LockSupport.park(blocker);  
            System.out.println("帶Blocker的線程被喚醒");
        }, "WithBlocker-Thread");
        
        Thread withoutBlocker = new Thread(() -> {
            System.out.println("無Blocker的線程開始阻塞");
            // 不推薦:無blocker的park方法
            LockSupport.park();  
            System.out.println("無Blocker的線程被喚醒");
        }, "WithoutBlocker-Thread");
        
        withBlocker.start();
        withoutBlocker.start();
        
        Thread.sleep(1000);
        
        // 在實際環境中使用jstack查看線程dump,區別明顯:
        // 有Blocker: "parking to wait for <0x00000000d5e8a6c0> (a java.lang.Object)"
        // 無Blocker: 只顯示在LockSupport.park處等待
        
        LockSupport.unpark(withBlocker);
        LockSupport.unpark(withoutBlocker);
        
        withBlocker.join();
        withoutBlocker.join();
    }
}

6. Condition接口:精準的線程協調器

6.1 Condition vs Object監視器

特性 Object.wait/notify Condition.await/signal
前置條件 必須在synchronized內 必須先獲取Lock
等待隊列 一個對象一個隊列 一個Lock多個Condition
精確通知 只能notifyAll或隨機 可以精確通知特定Condition
超時控制 有限支持 豐富的時間控制方法

6.2 Condition實戰:有界阻塞隊列

/**
 * 有界阻塞隊列 - Condition的經典應用
 * 功能:
 * - 隊列空時,消費者等待
 * - 隊列滿時,生產者等待
 */
public class BoundedBlockingQueue<T> {
    private final Object[] items;
    private int addIndex, removeIndex, count;
    
    private final Lock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();  // 非空條件
    private final Condition notFull = lock.newCondition();   // 非滿條件
    
    public BoundedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        items = new Object[capacity];
    }
    
    /**
     * 生產方法:隊列滿時阻塞
     */
    public void put(T item) throws InterruptedException {
        lock.lock();
        try {
            // 使用while防止虛假喚醒
            while (count == items.length) {
                System.out.println("隊列已滿,生產者等待...");
                notFull.await();  // 在notFull條件上等待
            }
            
            // 生產元素
            items[addIndex] = item;
            if (++addIndex == items.length) addIndex = 0;
            count++;
            
            System.out.println("生產: " + item + ", 當前數量: " + count);
            
            // 通知可能等待的消費者
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 消費方法:隊列空時阻塞
     */
    @SuppressWarnings("unchecked")
    public T take() throws InterruptedException {
        lock.lock();
        try {
            // 使用while防止虛假喚醒
            while (count == 0) {
                System.out.println("隊列為空,消費者等待...");
                notEmpty.await();  // 在notEmpty條件上等待
            }
            
            // 消費元素
            T item = (T) items[removeIndex];
            if (++removeIndex == items.length) removeIndex = 0;
            count--;
            
            System.out.println("消費: " + item + ", 當前數量: " + count);
            
            // 通知可能等待的生產者
            notFull.signal();
            return item;
        } finally {
            lock.unlock();
        }
    }
}

6.3 Condition內部機制:等待隊列與同步隊列的協作

/**
 * Condition內部工作機制解析
 */
public class ConditionInternalMechanism {
    /**
     * Condition內部有兩個重要隊列:
     * 
     * 1. 等待隊列(Condition隊列):單向鏈表
     *    firstWaiter → [thread|nextWaiter] → [thread|nextWaiter] → lastWaiter
     *    
     * 2. 同步隊列(AQS隊列):雙向鏈表  
     *    head ? [prev|thread|next] ? [prev|thread|next] ? tail
     * 
     * await過程:同步隊列 → 等待隊列
     * signal過程:等待隊列 → 同步隊列
     */
    
    /**
     * await方法核心流程:
     */
    public final void await() throws InterruptedException {
        // 1. 創建節點加入Condition等待隊列
        Node node = addConditionWaiter();
        
        // 2. 完全釋放鎖(保存重入狀態)
        int savedState = fullyRelease(node);
        
        // 3. 阻塞直到被signal或中斷
        while (!isOnSyncQueue(node)) {
            LockSupport.park(this);
            if (checkInterruptWhileWaiting(node) != 0) break;
        }
        
        // 4. 被喚醒后重新競爭鎖
        if (acquireQueued(node, savedState)) {
            // 處理中斷...
        }
    }
    
    /**
     * signal方法核心流程:
     */
    public final void signal() {
        // 1. 必須持有鎖才能調用
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
            
        // 2. 轉移等待隊列的第一個節點到同步隊列
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }
}

7. AQS同步隊列 vs Condition等待隊列

7.1 核心區別總結

特性 AQS同步隊列 Condition等待隊列
設計目的 管理鎖競爭的線程 管理條件等待的線程
數據結構 雙向鏈表 單向鏈表
節點狀態 SIGNAL, CANCELLED, 0, PROPAGATE CONDITION(-2)
隊列數量 每個AQS實例1個 每個Condition1個
線程行為 競爭鎖資源 等待特定條件滿足
喚醒方式 前驅節點釋放鎖時喚醒 其他線程調用signal()喚醒

7.2 隊列協作的完整示例

/**
 * 演示兩個隊列如何協作工作
 */
public class TwoQueuesCollaboration {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    
    public void demonstrate() throws InterruptedException {
        Thread waiter = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Waiter: 獲取鎖,準備await");
                
                // 此時:
                // - Waiter在同步隊列中(持有鎖)
                // - 等待隊列為空
                
                condition.await();  // 關鍵操作!
                
                // await內部完成:
                // 1. Waiter節點從同步隊列移到等待隊列
                // 2. 釋放鎖
                // 3. 阻塞等待
                
                System.out.println("Waiter: 被喚醒,重新獲得鎖");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        });
        
        Thread signaler = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Signaler: 獲取鎖,調用signal");
                
                // 此時:
                // - Signaler在同步隊列中(持有鎖)  
                // - Waiter在等待隊列中
                
                condition.signal();  // 關鍵操作!
                
                // signal內部完成:
                // 1. Waiter節點從等待隊列移到同步隊列
                // 2. 喚醒Waiter線程
                
                System.out.println("Signaler: signal完成");
            } finally {
                lock.unlock();  // 釋放鎖,Waiter有機會競爭鎖
            }
        });
        
        waiter.start();
        Thread.sleep(100);  // 確保waiter先執行
        signaler.start();
        
        waiter.join();
        signaler.join();
    }
}

8. 實戰指南:如何正確使用Java并發鎖

8.1 鎖使用的核心原則

原則1:永遠在finally塊中釋放鎖

/**
 * 正確的鎖釋放方式
 */
public class CorrectLockUsage {
    private final Lock lock = new ReentrantLock();
    
    // ? 正確做法
    public void correctMethod() {
        lock.lock();
        try {
            // 業務邏輯
            doBusiness();
        } finally {
            lock.unlock();  // 確保鎖被釋放
        }
    }
    
    // ? 錯誤做法
    public void wrongMethod() {
        lock.lock();
        doBusiness();
        lock.unlock();  // 如果doBusiness拋出異常,鎖不會被釋放!
    }
    
    private void doBusiness() {
        // 可能拋出異常的業務邏輯
        if (Math.random() > 0.5) {
            throw new RuntimeException("業務異常");
        }
    }
}

原則2:避免鎖嵌套,預防死鎖

/**
 * 死鎖預防示例
 */
public class DeadlockPrevention {
    private final Lock lockA = new ReentrantLock();
    private final Lock lockB = new ReentrantLock();
    
    // ? 容易導致死鎖的做法
    public void potentialDeadlock() {
        lockA.lock();
        try {
            // 一些操作...
            lockB.lock();  // 如果另一個線程以相反順序獲取鎖,可能死鎖
            try {
                // 更多操作...
            } finally {
                lockB.unlock();
            }
        } finally {
            lockA.unlock();
        }
    }
    
    // ? 使用tryLock避免死鎖
    public void safeMethod() {
        while (true) {
            if (lockA.tryLock()) {
                try {
                    if (lockB.tryLock()) {
                        try {
                            // 成功獲取兩個鎖,執行業務
                            doBusiness();
                            return;  // 成功完成,退出循環
                        } finally {
                            lockB.unlock();
                        }
                    }
                } finally {
                    lockA.unlock();
                }
            }
            // 獲取鎖失敗,短暫休息后重試
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    
    // ? 使用固定的鎖獲取順序
    public void fixedOrderMethod(Object resource1, Object resource2) {
        // 通過hash值確定固定的獲取順序
        int hash1 = System.identityHashCode(resource1);
        int hash2 = System.identityHashCode(resource2);
        
        if (hash1 < hash2) {
            lockA.lock();
            lockB.lock();
        } else {
            lockB.lock();
            lockA.lock();
        }
        
        try {
            doBusiness();
        } finally {
            lockA.unlock();
            lockB.unlock();
        }
    }
    
    private void doBusiness() {}
}

8.2 各組件最佳實踐案例

8.2.1 ReentrantLock最佳實踐:連接池管理

/**
 * 基于ReentrantLock的簡單數據庫連接池
 * 特性:支持超時獲取、中斷響應、連接驗證
 */
public class DatabaseConnectionPool {
    private final LinkedList<Connection> pool = new LinkedList<>();
    private final ReentrantLock lock = new ReentrantLock(true);  // 公平鎖
    private final Condition notEmpty = lock.newCondition();
    private final int maxSize;
    private final long maxWaitTime;
    
    public DatabaseConnectionPool(int maxSize, long maxWaitMillis) {
        this.maxSize = maxSize;
        this.maxWaitTime = maxWaitMillis;
        initializePool();
    }
    
    /**
     * 獲取連接 - 支持超時和中斷
     */
    public Connection getConnection() throws InterruptedException, TimeoutException {
        lock.lock();
        try {
            long endTime = System.currentTimeMillis() + maxWaitTime;
            
            while (pool.isEmpty()) {
                long remainingTime = endTime - System.currentTimeMillis();
                if (remainingTime <= 0) {
                    throw new TimeoutException("獲取連接超時");
                }
                
                // 等待連接可用,支持超時
                if (!notEmpty.await(remainingTime, TimeUnit.MILLISECONDS)) {
                    throw new TimeoutException("獲取連接超時");
                }
            }
            
            // 獲取并驗證連接
            Connection conn = pool.removeFirst();
            if (!isConnectionValid(conn)) {
                conn = createNewConnection();
            }
            return conn;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 歸還連接
     */
    public void returnConnection(Connection conn) {
        if (conn == null) return;
        
        lock.lock();
        try {
            if (pool.size() < maxSize && isConnectionValid(conn)) {
                pool.addLast(conn);
                notEmpty.signal();  // 通知等待的線程
            } else {
                // 連接池已滿或連接無效,關閉連接
                closeConnection(conn);
            }
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 嘗試獲取連接(非阻塞)
     */
    public Connection tryGetConnection() {
        if (lock.tryLock()) {
            try {
                if (!pool.isEmpty()) {
                    Connection conn = pool.removeFirst();
                    if (isConnectionValid(conn)) {
                        return conn;
                    }
                }
            } finally {
                lock.unlock();
            }
        }
        return null;
    }
    
    private boolean isConnectionValid(Connection conn) {
        // 連接有效性檢查邏輯
        try {
            return conn != null && !conn.isClosed() && conn.isValid(2);
        } catch (SQLException e) {
            return false;
        }
    }
    
    private Connection createNewConnection() {
        // 創建新連接的邏輯
        return null; // 簡化實現
    }
    
    private void closeConnection(Connection conn) {
        // 關閉連接的邏輯
    }
    
    private void initializePool() {
        // 初始化連接池
        for (int i = 0; i < maxSize / 2; i++) {
            pool.add(createNewConnection());
        }
    }
}

8.2.2 讀寫鎖最佳實踐:配置中心

/**
 * 基于讀寫鎖的配置中心
 * 特性:高頻讀取,低頻更新,保證數據一致性
 */
public class ConfigurationCenter {
    private final Map<String, String> configs = new HashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    
    /**
     * 獲取配置 - 高頻操作,使用讀鎖
     */
    public String getConfig(String key) {
        readLock.lock();
        try {
            String value = configs.get(key);
            // 模擬配置讀取的耗時操作
            simulateProcess(1);
            return value;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 批量獲取配置 - 讀鎖支持并發
     */
    public Map<String, String> getConfigs(Set<String> keys) {
        readLock.lock();
        try {
            Map<String, String> result = new HashMap<>();
            for (String key : keys) {
                result.put(key, configs.get(key));
            }
            simulateProcess(keys.size());
            return result;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 更新配置 - 低頻操作,使用寫鎖
     */
    public void updateConfig(String key, String value) {
        writeLock.lock();
        try {
            // 模擬配置更新的耗時操作
            simulateProcess(10);
            configs.put(key, value);
            System.out.println("配置更新: " + key + " = " + value);
        } finally {
            writeLock.unlock();
        }
    }
    
    /**
     * 批量更新配置 - 寫鎖保證原子性
     */
    public void updateConfigs(Map<String, String> newConfigs) {
        writeLock.lock();
        try {
            simulateProcess(newConfigs.size() * 5);
            configs.putAll(newConfigs);
            System.out.println("批量更新配置: " + newConfigs.size() + " 項");
        } finally {
            writeLock.unlock();
        }
    }
    
    /**
     * 熱更新配置 - 使用鎖降級保證數據一致性
     */
    public void hotUpdateConfig(String key, String value) {
        // 先獲取寫鎖進行更新
        writeLock.lock();
        try {
            // 更新配置
            configs.put(key, value);
            System.out.println("熱更新配置: " + key + " = " + value);
            
            // 鎖降級:在釋放寫鎖前獲取讀鎖
            readLock.lock();
        } finally {
            writeLock.unlock();  // 鎖降級完成
        }
        
        try {
            // 在讀鎖保護下進行后續操作(如通知觀察者、記錄日志等)
            notifyConfigChange(key, value);
            logConfigChange(key, value);
        } finally {
            readLock.unlock();
        }
    }
    
    private void notifyConfigChange(String key, String value) {
        // 通知配置變更觀察者
        simulateProcess(2);
    }
    
    private void logConfigChange(String key, String value) {
        // 記錄配置變更日志
        simulateProcess(1);
    }
    
    private void simulateProcess(int milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

8.2.3 Condition最佳實踐:任務調度器

/**
 * 基于Condition的任務調度器
 * 特性:支持任務等待、超時控制、優雅關閉
 */
public class TaskScheduler {
    private final PriorityBlockingQueue<Task> taskQueue = new PriorityBlockingQueue<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition taskAvailable = lock.newCondition();
    private final Condition schedulerStopped = lock.newCondition();
    private volatile boolean running = true;
    private final Thread workerThread;
    
    public TaskScheduler() {
        this.workerThread = new Thread(this::processTasks, "TaskScheduler-Worker");
        this.workerThread.start();
    }
    
    /**
     * 提交任務 - 支持超時
     */
    public boolean submitTask(Task task, long timeout, TimeUnit unit) 
            throws InterruptedException {
        lock.lock();
        try {
            long deadline = System.nanoTime() + unit.toNanos(timeout);
            
            // 等待直到有空間或超時
            while (taskQueue.size() >= 1000) {  // 隊列容量限制
                long remaining = deadline - System.nanoTime();
                if (remaining <= 0) {
                    return false;  // 超時
                }
                if (!taskAvailable.await(remaining, TimeUnit.NANOSECONDS)) {
                    return false;  // 超時
                }
            }
            
            taskQueue.offer(task);
            taskAvailable.signal();  // 通知工作線程
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 立即提交任務(非阻塞)
     */
    public boolean submitTaskNow(Task task) {
        lock.lock();
        try {
            if (taskQueue.size() >= 1000) {
                return false;  // 隊列已滿
            }
            taskQueue.offer(task);
            taskAvailable.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 優雅關閉 - 等待所有任務完成
     */
    public void shutdown() throws InterruptedException {
        lock.lock();
        try {
            running = false;
            taskAvailable.signalAll();  // 喚醒工作線程
            
            // 等待任務隊列清空
            while (!taskQueue.isEmpty()) {
                schedulerStopped.await(1, TimeUnit.SECONDS);
            }
        } finally {
            lock.unlock();
        }
        
        workerThread.join();
    }
    
    /**
     * 立即關閉
     */
    public void shutdownNow() {
        lock.lock();
        try {
            running = false;
            taskQueue.clear();
            taskAvailable.signalAll();
        } finally {
            lock.unlock();
        }
    }
    
    private void processTasks() {
        while (running || !taskQueue.isEmpty()) {
            try {
                Task task = taskQueue.poll(1, TimeUnit.SECONDS);
                if (task != null) {
                    executeTask(task);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        
        // 通知關閉完成
        lock.lock();
        try {
            schedulerStopped.signalAll();
        } finally {
            lock.unlock();
        }
    }
    
    private void executeTask(Task task) {
        try {
            task.execute();
        } catch (Exception e) {
            System.err.println("任務執行失敗: " + e.getMessage());
        }
    }
    
    public static class Task implements Comparable<Task> {
        private final Runnable runnable;
        private final long scheduledTime;
        private final int priority;
        
        public Task(Runnable runnable, long delay, TimeUnit unit, int priority) {
            this.runnable = runnable;
            this.scheduledTime = System.nanoTime() + unit.toNanos(delay);
            this.priority = priority;
        }
        
        public void execute() {
            runnable.run();
        }
        
        @Override
        public int compareTo(Task other) {
            int timeCompare = Long.compare(this.scheduledTime, other.scheduledTime);
            if (timeCompare != 0) {
                return timeCompare;
            }
            return Integer.compare(other.priority, this.priority);  // 優先級高的在前
        }
    }
}

8.2.4 LockSupport最佳實踐:自定義同步器

/**
 * 基于LockSupport的自定義閉鎖
 * 特性:一次性屏障,支持超時和中斷
 */
public class SimpleCountDownLatch {
    private volatile int count;
    private final Queue<Thread> waiters = new ConcurrentLinkedQueue<>();
    
    public SimpleCountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("計數不能為負");
        this.count = count;
    }
    
    /**
     * 等待閉鎖打開
     */
    public void await() throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        if (count <= 0) {
            return;  // 已經打開
        }
        
        // 使用LockSupport阻塞
        Thread current = Thread.currentThread();
        waiters.offer(current);
        
        // 雙重檢查避免錯過信號
        if (count > 0) {
            LockSupport.park(this);
        }
        
        // 檢查是否被中斷喚醒
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
    }
    
    /**
     * 超時等待
     */
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        if (count <= 0) {
            return true;
        }
        
        long deadline = System.nanoTime() + unit.toNanos(timeout);
        Thread current = Thread.currentThread();
        waiters.offer(current);
        
        try {
            while (count > 0) {
                long remaining = deadline - System.nanoTime();
                if (remaining <= 0) {
                    return false;  // 超時
                }
                LockSupport.parkNanos(this, remaining);
                
                if (Thread.interrupted()) {
                    throw new InterruptedException();
                }
            }
            return true;
        } finally {
            waiters.remove(current);
        }
    }
    
    /**
     * 計數減1
     */
    public void countDown() {
        if (count <= 0) {
            return;  // 已經打開
        }
        
        if (--count == 0) {
            // 喚醒所有等待線程
            Thread waiter;
            while ((waiter = waiters.poll()) != null) {
                LockSupport.unpark(waiter);
            }
        }
    }
    
    /**
     * 獲取當前計數
     */
    public int getCount() {
        return count;
    }
}

8.3 性能優化和陷阱避免

8.3.1 鎖性能優化技巧

/**
 * 鎖性能優化實踐
 */
public class LockPerformanceOptimization {
    private final ReentrantLock lock = new ReentrantLock();
    private int counter = 0;
    private long lastLogTime = System.currentTimeMillis();
    
    // ? 鎖粒度太粗
    public void coarseGrainedLock() {
        lock.lock();
        try {
            // 包含非臨界區操作
            loadFromDatabase();  // 耗時IO操作
            counter++;           // 真正的臨界區
            saveToDatabase();    // 耗時IO操作
        } finally {
            lock.unlock();
        }
    }
    
    // ? 鎖粒度細化
    public void fineGrainedLock() {
        // 在鎖外執行IO操作
        loadFromDatabase();
        
        lock.lock();
        try {
            counter++;  // 只保護真正的臨界區
        } finally {
            lock.unlock();
        }
        
        saveToDatabase();  // 在鎖外執行IO操作
    }
    
    // ? 使用原子變量替代鎖
    private final AtomicInteger atomicCounter = new AtomicInteger(0);
    
    public void atomicOperation() {
        atomicCounter.incrementAndGet();  // 無鎖操作,性能更高
    }
    
    // ? 讀寫分離
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private volatile boolean initialized = false;
    
    public void lazyInit() {
        if (!initialized) {
            writeLock.lock();
            try {
                // 雙重檢查
                if (!initialized) {
                    performInitialization();
                    initialized = true;
                }
            } finally {
                writeLock.unlock();
            }
        }
        
        // 后續讀操作使用讀鎖
        readLock.lock();
        try {
            useInitializedResource();
        } finally {
            readLock.unlock();
        }
    }
    
    private void loadFromDatabase() {
        // 模擬數據庫加載
    }
    
    private void saveToDatabase() {
        // 模擬數據庫保存
    }
    
    private void performInitialization() {
        // 初始化操作
    }
    
    private void useInitializedResource() {
        // 使用初始化后的資源
    }
}

8.3.2 常見陷阱及避免方法

/**
 * 并發編程常見陷阱及解決方案
 */
public class ConcurrentPitfalls {
    
    // 陷阱1:在鎖內調用外部方法(可能發生死鎖)
    public void trap1() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            externalMethod();  // 危險!可能獲取其他鎖
        } finally {
            lock.unlock();
        }
    }
    
    // 解決方案:減少鎖內代碼,只包含必要的臨界區操作
    public void solution1() {
        ReentrantLock lock = new ReentrantLock();
        // 在鎖外準備數據
        Object data = prepareData();
        
        lock.lock();
        try {
            // 只執行必須同步的操作
            updateSharedState(data);
        } finally {
            lock.unlock();
        }
    }
    
    // 陷阱2:忘記在finally中釋放鎖
    public void trap2() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        if (someCondition()) {
            return;  // 忘記釋放鎖!
        }
        lock.unlock();
    }
    
    // 解決方案:使用try-finally模板
    public void solution2() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            if (someCondition()) {
                return;
            }
            // 其他操作
        } finally {
            lock.unlock();  // 確保釋放
        }
    }
    
    // 陷阱3:在Condition.await()中使用if而不是while
    public void trap3() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        boolean conditionMet = false;
        
        lock.lock();
        try {
            if (!conditionMet) {  // 錯誤!應該用while
                condition.await();
            }
            // 可能被虛假喚醒,條件仍未滿足
        } finally {
            lock.unlock();
        }
    }
    
    // 解決方案:總是使用while循環檢查條件
    public void solution3() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        boolean conditionMet = false;
        
        lock.lock();
        try {
            while (!conditionMet) {  // 正確!防止虛假喚醒
                condition.await();
            }
            // 條件確定滿足
        } finally {
            lock.unlock();
        }
    }
    
    private boolean someCondition() {
        return Math.random() > 0.5;
    }
    
    private Object prepareData() {
        return new Object();
    }
    
    private void updateSharedState(Object data) {
        // 更新共享狀態
    }
    
    private void externalMethod() {
        // 可能獲取其他鎖的外部方法
    }
}

8.4 監控和調試技巧

8.4.1 鎖監控工具

/**
 * 鎖監控和診斷工具
 */
public class LockMonitor {
    
    /**
     * 監控鎖競爭情況
     */
    public static void monitorLockContention(ReentrantLock lock, String lockName) {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(5000);  // 每5秒檢查一次
                    
                    System.out.printf("鎖[%s]監控: %n", lockName);
                    System.out.printf("  - 等待隊列長度: %d%n", lock.getQueueLength());
                    System.out.printf("  - 是否有等待線程: %b%n", lock.hasQueuedThreads());
                    System.out.printf("  - 是否被當前線程持有: %b%n", lock.isHeldByCurrentThread());
                    System.out.printf("  - 重入次數: %d%n", lock.getHoldCount());
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }, "LockMonitor-" + lockName).start();
    }
    
    /**
     * 死鎖檢測
     */
    public static void detectDeadlock() {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadMXBean.findDeadlockedThreads();
        
        if (threadIds != null) {
            System.err.println("檢測到死鎖!");
            ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadIds);
            
            for (ThreadInfo threadInfo : threadInfos) {
                System.err.println("死鎖線程: " + threadInfo.getThreadName());
                System.err.println("阻塞對象: " + threadInfo.getLockName());
                System.err.println("阻塞者: " + threadInfo.getLockOwnerName());
            }
        }
    }
    
    /**
     * 鎖性能統計
     */
    public static class LockStats {
        private final ReentrantLock lock;
        private long lockAcquireCount = 0;
        private long totalWaitTime = 0;
        private long maxWaitTime = 0;
        
        public LockStats(ReentrantLock lock) {
            this.lock = lock;
        }
        
        public void recordLockAcquire(long waitTime) {
            lockAcquireCount++;
            totalWaitTime += waitTime;
            maxWaitTime = Math.max(maxWaitTime, waitTime);
        }
        
        public void printStats() {
            System.out.printf("鎖統計: %n");
            System.out.printf("  - 獲取次數: %d%n", lockAcquireCount);
            System.out.printf("  - 平均等待時間: %.2fms%n", 
                lockAcquireCount > 0 ? (double)totalWaitTime / lockAcquireCount : 0);
            System.out.printf("  - 最大等待時間: %dms%n", maxWaitTime);
            System.out.printf("  - 當前等待線程: %d%n", lock.getQueueLength());
        }
    }
}

總結:正確使用并發鎖的黃金法則

  1. 明確性:清楚知道每個鎖保護的是什么數據
  2. 最小化:鎖粒度盡可能小,持有時間盡可能短
  3. 一致性:按照固定順序獲取多個鎖
  4. 可靠性:總是在finally塊中釋放鎖
  5. 可中斷性:對長時間操作使用可中斷的鎖獲取方式
  6. 監控性:對關鍵鎖進行監控和統計

Java并(bing)發(fa)包(bao)中的鎖機制(zhi)通過精(jing)妙的設計實現了(le)高(gao)效、靈活的線程同步(bu):

  • AQS是基石:提供了同步隊列管理和狀態控制的基礎設施
  • Lock接口是門面:定義了豐富的鎖操作API
  • 重入鎖解決重入問題:支持同一線程多次獲取鎖
  • 讀寫鎖優化讀多寫少場景:通過鎖分離提升并發性能
  • LockSupport提供底層阻塞能力:線程控制的精準工具
  • Condition實現精確線程協調:多條件等待隊列支持復雜同步邏輯

記住這個核心關系:Lock → AQS → Condition → LockSupport,它們共(gong)同構(gou)成了(le)Java并發鎖機(ji)(ji)制(zhi)的(de)完整體系。理解這(zhe)些組件的(de)內部機(ji)(ji)制(zhi),能(neng)(neng)夠幫助(zhu)我們正確選(xuan)擇和使(shi)用合適(shi)的(de)同步工具,診斷(duan)和解決(jue)復雜的(de)并發問題,設(she)計高(gao)性能(neng)(neng)的(de)并發組件。

記住(zhu)這些原則(ze)和(he)(he)最(zui)佳(jia)實踐,你就(jiu)能構(gou)建出高效、可(ke)靠的并(bing)發程(cheng)序。并(bing)發編程(cheng)雖(sui)然復雜(za),但通過正確的工(gong)具和(he)(he)方法,完全(quan)可(ke)以駕馭(yu)!

posted @ 2025-10-29 08:42  佛祖讓我來巡山  閱讀(158)  評論(0)    收藏  舉報

佛祖讓我來巡山博客站 - 創建于 2018-08-15

開發工程師個人站(zhan),內(nei)容主要是網站(zhan)開發方面的技術文章,大部分(fen)來(lai)自學習或工作(zuo),部分(fen)來(lai)源(yuan)于網絡,希望對大家(jia)有(you)所(suo)幫助。