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

Java 同步核心組件 Mutex 深度剖析:非重入互斥鎖的實現與應用

     編輯:Java 相關知識

Doug Lea Concurrent 套件定義 Sync 介面作為所有同步原語(鎖、閘門、條件變數)的統一抽象,Mutex 是其最基礎的非重入互斥鎖實現。本文剖析源碼並示範精細鎖定鏈表應用。

Sync 介面:同步操作的統一契約

public interface Sync {
    void acquire() throws InterruptedException;     // 獲取許可(阻塞)
    boolean attempt(long msecs) throws InterruptedException; // 嘗試獲取(超時)
    void release();                                 // 釋放許可
}

優勢:超越 synchronized 的方法/區塊限制,鎖物件可跨方法、跨物件傳遞,實現靈活的同步控制。

標準使用模式:配合 try-finally 確保釋放

class X {
    Sync gate; // Mutex 或其他 Sync 實現
    
    public void m() {
        try {
            gate.acquire();
            try {
                // 臨界區邏輯
            } finally {
                gate.release(); // 即使拋出異常也能釋放
            }
        } catch (InterruptedException ex) {
            // 處理中斷
        }
    }
}

release() 不拋出 InterruptedException,適合放在 finally 中。

Mutex 源碼深度解析

public class Mutex implements Sync {
    protected boolean inuse = false;
    
    public void acquire() throws InterruptedException {
        if (Thread.interrupted()) throw new InterruptedException(); // (1) 快速失敗
        synchronized (this) {
            try {
                while (inuse) wait(); // 自旋等待
                inuse = true;
            } catch (InterruptedException ex) {
                notify(); // (2) 被中斷時喚醒其他等待者
                throw ex;
            }
        }
    }
    
    public synchronized void release() {
        inuse = false;
        notify(); // 喚醒單一等待者
    }
    
    public boolean attempt(long msecs) throws InterruptedException {
        if (Thread.interrupted()) throw new InterruptedException();
        synchronized (this) {
            if (!inuse) { inuse = true; return true; }
            if (msecs <= 0) return false;
            
            long waitTime = msecs;
            long start = System.currentTimeMillis();
            try {
                for (;;) {
                    wait(waitTime);
                    if (!inuse) { inuse = true; return true; }
                    waitTime = msecs - (System.currentTimeMillis() - start);
                    if (waitTime <= 0) return false; // (3) 超時返回
                }
            } catch (InterruptedException ex) {
                notify(); throw ex;
            }
        }
    }
}

關鍵設計細節

  1. 雙重中斷檢查:acquire() 開頭與 wait() 捕獲處均檢查中斷狀態。Thread.interrupted() 清除標誌位,若線程已被中斷則立即拋出異常,避免進入等待狀態。
  2. 中斷時通知:捕獲 InterruptedException 後呼叫 notify() 喚醒其他等待者,防止信號遺失導致永久阻塞。
  3. 粗略計時:attempt() 基於 Object.wait(long) 實現,非精確時鐘,僅供粗略超時控制。

實戰應用:精細鎖定鏈表

每個節點持有獨立 Mutex,實現「手把手」鎖遞移,大幅提升並行遍歷效能:

class Node {
    Object item; Node next;
    Mutex lock = new Mutex(); // 每節點一把鎖
    
    Node(Object x, Node n) { item = x; next = n; }
}

class List {
    protected Node head;
    
    protected synchronized Node getHead() { return head; } // 僅保護 head 參考
    
    boolean search(Object x) throws InterruptedException {
        Node p = getHead();
        if (p == null) return false;
        
        p.lock.acquire(); // 獲取首節點鎖
        try {
            for (;;) {
                if (x.equals(p.item)) { p.lock.release(); return true; }
                
                Node nextp = p.next;
                if (nextp == null) { p.lock.release(); return false; }
                
                try { nextp.lock.acquire(); } // 先獲取下一節點鎖
                catch (InterruptedException ex) { p.lock.release(); throw ex; }
                
                p.lock.release(); // 再釋放當前節點鎖
                p = nextp;
            }
        } finally { /* 確保釋放 */ }
    }
    
    synchronized void add(Object x) { head = new Node(x, head); }
}

總結

  • Mutex 實現 Sync 介面,提供非重入、可中斷、可超時的互斥語義
  • 源碼展示標準監視器模式:synchronized + wait/notify + 狀態旗標
  • 精細鎖定適用於高爭用資料結構(鏈表、樹),將鎖粒度縮小至單一節點
  • 生產環境建議直接使用 java.util.concurrent.locks.ReentrantLock(JDK 1.5+ 內建,支援重入、公平性、條件變數等進階特性)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved