Lock锁的原理是什么

发布时间:2021-10-14 13:58:45 作者:iii
来源:亿速云 阅读:208
# 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字需要补充更多示例代码和性能测试数据。如需完整版本,可提供具体扩展方向要求。

推荐阅读:
  1. mysql 间隙锁 Gap Lock
  2. MYSQL METADATA LOCK(MDL LOCK)MDL锁问题的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mysql

上一篇:基于AppServ,XAMPP,WAMP如何配置php.ini去掉警告信息

下一篇:SQL Server 2008 R2:error 26如何开启远程连接

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》