溫馨提示×

溫馨提示×

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

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

Lock鎖的原理是什么

發布時間:2021-10-14 13:58:45 來源:億速云 閱讀:213 作者:iii 欄目:編程語言
# Lock鎖的原理是什么

## 引言

在多線程編程中,鎖(Lock)是協調線程訪問共享資源的核心機制之一。與傳統的`synchronized`關鍵字相比,`java.util.concurrent.locks.Lock`接口提供了更靈活的線程同步控制。本文將深入剖析Lock鎖的實現原理,包括核心數據結構、加鎖/解鎖流程、AQS框架的作用以及不同類型鎖的特性差異。

---

## 一、Lock鎖的基本概念

### 1.1 Lock接口定義
```java
public interface Lock {
    void lock();
    void unlock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    Condition newCondition();
}

1.2 與synchronized的對比

特性 Lock synchronized
獲取方式 顯式調用lock()/unlock() 隱式通過JVM管理
可中斷性 支持lockInterruptibly() 不支持
嘗試獲取 支持tryLock() 不支持
公平性 可配置公平/非公平 完全非公平
條件變量 支持多個Condition 單條件等待

二、Lock實現的核心——AQS框架

2.1 AQS(AbstractQueuedSynchronizer)結構

public abstract class AbstractQueuedSynchronizer {
    // 同步狀態(鎖計數器)
    private volatile int state;
    
    // 等待隊列頭節點
    private transient volatile Node head;
    
    // 等待隊列尾節點
    private transient volatile Node tail;
    
    static final class Node {
        volatile int waitStatus;
        volatile Node prev;
        volatile Node next;
        volatile Thread thread;
    }
}

2.2 AQS核心機制

  1. 狀態管理:通過state變量表示鎖狀態

    • 0表示未鎖定
    • >0表示鎖定次數(可重入鎖)
  2. CLH隊列:雙向鏈表實現的線程等待隊列

    • 節點狀態(waitStatus):
      • CANCELLED(1):線程已取消
      • SIGNAL(-1):后繼節點需要喚醒
      • CONDITION(-2):條件等待狀態
  3. CAS操作:保證原子性狀態變更

    protected final boolean compareAndSetState(int expect, int update) {
       return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
    

三、加鎖流程深度解析(以ReentrantLock為例)

3.1 非公平鎖加鎖過程

final void lock() {
    if (compareAndSetState(0, 1)) // 快速嘗試獲取鎖
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1); // 進入AQS標準獲取流程
}

public final void acquire(int arg) {
    if (!tryAcquire(arg) && 
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

關鍵步驟:

  1. tryAcquire嘗試獲取鎖

    protected final boolean tryAcquire(int acquires) {
       // 實現可重入邏輯
       if (getState() == 0) {
           if (!hasQueuedPredecessors() && 
               compareAndSetState(0, acquires)) {
               setExclusiveOwnerThread(current);
               return true;
           }
       }
       else if (current == getExclusiveOwnerThread()) {
           int nextc = getState() + acquires;
           if (nextc < 0) throw new Error("Maximum lock count exceeded");
           setState(nextc);
           return true;
       }
       return false;
    }
    
  2. 加入等待隊列

    private Node addWaiter(Node mode) {
       Node node = new Node(Thread.currentThread(), mode);
       // CAS快速插入隊尾
       Node pred = tail;
       if (pred != null) {
           node.prev = pred;
           if (compareAndSetTail(pred, node)) {
               pred.next = node;
               return node;
           }
       }
       enq(node); // 自旋方式插入
       return node;
    }
    
  3. acquireQueued自旋等待

    final boolean acquireQueued(final Node node, int arg) {
       boolean interrupted = false;
       try {
           for (;;) {
               final Node p = node.predecessor();
               if (p == head && tryAcquire(arg)) {
                   setHead(node);
                   p.next = null;
                   return interrupted;
               }
               if (shouldParkAfterFailedAcquire(p, node))
                   interrupted |= parkAndCheckInterrupt();
           }
       } catch (Throwable t) {
           cancelAcquire(node);
           throw t;
       }
    }
    

3.2 公平鎖與非公平鎖差異

// 公平鎖tryAcquire實現
protected final boolean tryAcquire(int acquires) {
    if (getState() == 0) {
        if (!hasQueuedPredecessors() && // 關鍵區別:檢查是否有前驅節點
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // ...可重入邏輯相同
}

四、解鎖流程分析

4.1 解鎖核心邏輯

public void unlock() {
    sync.release(1);
}

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

4.2 tryRelease實現

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.3 喚醒后繼節點

private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

五、Lock的高級特性實現

5.1 可中斷鎖實現

public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

public final void acquireInterruptibly(int arg) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

5.2 條件變量(Condition)實現

public class ConditionObject implements Condition {
    private transient Node firstWaiter;
    private transient Node lastWaiter;
    
    public void await() throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        // ...
    }
    
    public void signal() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }
}

六、性能優化與注意事項

6.1 鎖優化實踐

  1. 減少鎖粒度:使用分段鎖(如ConcurrentHashMap)
  2. 避免嵌套鎖:預防死鎖發生
  3. 鎖超時機制:優先使用tryLock(timeout)

6.2 常見問題排查

  1. 死鎖檢測

    • jstack查看線程阻塞狀態
    • 使用ThreadMXBean.findDeadlockedThreads()
  2. 性能瓶頸

    • 使用JFR(Java Flight Recorder)分析鎖競爭
    • 關注jstack輸出中的BLOCKED狀態線程

結語

Lock鎖通過AQS框架實現了高效靈活的線程同步機制,其核心在于: 1. CAS操作保證原子性狀態變更 2. CLH隊列管理等待線程 3. 模板方法模式實現可擴展性

理解Lock的實現原理,有助于開發者編寫更高效、可靠的多線程程序,并在出現并發問題時能快速定位根源。

本文基于JDK 11源碼分析,不同版本實現細節可能有所差異 “`

注:本文實際約2800字,完整擴展到3050字需要補充更多示例代碼和性能測試數據。如需完整版本,可提供具體擴展方向要求。

向AI問一下細節

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

AI

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