目录
- 1.说明
- 2.锁的状态
- 3.锁的实现方式
- 4.AQS 的核心组件
- 5.锁获取和释放的过程
- 5.1 获取锁
- 5.2 释放锁
- 6.可重入性
- 7.公平锁与非公平锁
- 8.锁的中断响应
1.说明
- 1.ReentrantLock 是 Java 中 java.util.concurrent.locks 包提供的一个可重入的互斥锁。
- 2.它提供了与 synchronized 关键字类似的同步功能,但比 synchronized 更加灵活和强大。
- 3.ReentrantLock 支持两种锁模式:公平锁和非公平锁。
2.锁的状态
- 1.ReentrantLock 内部维护了一个锁的状态,用于表示锁是否被某个线程持有,以及被持有的次数。
- 2.锁的状态通常用一个整数(通常是32位)来表示,其中高位的几位用于表示锁的状态,低位的几位用于记录重入的次数(即同一个线程持有锁的次数)。
3.锁的实现方式
- 1.ReentrantLock 的实现依赖于底层的同步机制,如 AbstractQueuedSynchronizer(简称 AQS)。AQS 是一个用于构建锁或其他同步组件的框架,它定义了一套多线程访问共享资源的同步器。
4.AQS 的核心组件
- 1.同步队列(Sync Queue):一个FIFO队列,用于存储等待获取锁的线程。
- 2.状态字段(State):一个整数,用于表示锁的状态和重入次数。
- 3.独占模式(Exclusive Mode):ReentrantLock 在默认情况下是独占锁,即一次只能有一个线程持有锁。
5.锁获取和释放的过程
5.1 获取锁
- 1.尝试获取锁:当一个线程尝试获取锁时,它会首先尝试通过CAS(Compare-And-Swap)操作将锁的状态从“未锁定”(0)修改为当前线程的ID(或其他表示锁持有的值)。如果CAS操作成功,则线程成功获取锁,并增加重入次数。
- 2.加入同步队列:如果CAS操作失败(即锁已被其他线程持有),则当前线程会被封装成一个节点(Node),并加入到同步队列的尾部。线程会进入一个自旋状态,不断尝试通过CAS操作获取锁,或者通过 park 方法挂起自己,等待被唤醒。
5.2 释放锁
- 1.减少重入次数:当持有锁的线程释放锁时,它会首先减少重入次数。如果重入次数变为0,则锁的状态会被设置为“未锁定”。
- 2.唤醒后继节点:如果锁状态变为“未锁定”,则持有锁的线程会唤醒同步队列中的下一个等待线程,使其有机会尝试获取锁。
6.可重入性
- 1.ReentrantLock 是可重入的,这意味着同一个线程可以多次获取同一个锁而不会导致死锁。
- 2.这是通过维护一个重入次数来实现的。
- 3.每次线程获取锁时,重入次数加1;每次释放锁时,重入次数减1。
- 4.只有当重入次数为0时,锁才会真正被释放。
7.公平锁与非公平锁
- 1.公平锁:按照线程请求锁的顺序来分配锁,即先请求的线程先获得锁。这通常会导致较长的等待时间,但可以避免线程饥饿。
- 2.非公平锁:不保证线程获取锁的顺序,可能会允许插队。这通常会导致较短的等待时间,但可能会导致线程饥饿。
8.锁的中断响应
- 1.ReentrantLock 支持中断响应的锁获取操作。如果线程在尝试获取锁时被中断,它可以立即响应中断,而不是一直等待下去。