Lock 底层原理
Lock 底层原理
程序员朱永胜有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步, 认准
https://blog.zysicyj.top
全网最细面试题手册,支持艾宾浩斯记忆法。这是一份最全面、最详细、最高质量的 java 面试题,不建议你死记硬背,只要每天复习一遍,有个大概印象就行了。https://store.amazingmemo.com/chapterDetail/1685324709017001`
Lock 底层原理
在 Java 中,锁(Lock)是用来控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对它进行操作。Java 中的锁分为内置锁(synchronized 关键字实现)和显式锁(java.util.concurrent.locks 包中的类实现,如 ReentrantLock
)。这里我们主要讨论显式锁的底层原理。
ReentrantLock
ReentrantLock
是 java.util.concurrent.locks
包中的一个重入锁,它实现了 Lock
接口,并提供了与 synchronized
关键字类似的同步功能,但它比 synchronized
提供了更高的处理锁的灵活性。
基本结构
ReentrantLock
内部维护了一个同步器 AbstractQueuedSynchronizer
(简称 AQS),这是实现锁机制的框架。AQS 使用一个 int 成员变量来表示同步状态,以及一个 FIFO 队列来管理线程的排队工作。
锁的获取与释放
当一个线程尝试获取锁时,AQS 会根据锁的状态决定是否需要排队等待。如果锁未被其他线程持有,那么当前线程可以获取锁并将同步状态设置为 1。如果锁已经被其他线程持有,当前线程就会进入等待队列,直到锁被释放。
对于可重入锁,如果当前线程已经持有锁,那么它可以再次获取锁,同步状态会相应地增加。
当线程执行完毕后,它会释放锁,这通常是通过调用 unlock()
方法来完成的。释放锁意味着同步状态要减 1,当状态为 0 时,表示锁完全释放。如果有其他线程在等待这个锁,那么 AQS 会唤醒队列中的下一个线程。
公平锁与非公平锁
ReentrantLock
提供了公平锁和非公平锁两种模式:
- 公平锁:线程获取锁的顺序是按照它们请求锁的顺序来分配的,即先来先得。
- 非公平锁:当锁被释放时,任何一个等待锁的线程都有机会获取锁,这可能会导致某些线程饿死(即永远获取不到锁)。
公平锁通过维护一个有序队列来实现,而非公平锁则可能会在锁释放时立即尝试获取锁,这通常会有更好的性能,但是不保证等待时间的公平性。
底层同步队列
AQS 使用一个双向链表来实现同步队列,每个节点包含了线程的引用、等待状态等信息。当线程获取不到锁时,它会被包装成一个节点加入到队列的尾部,并在那里进行等待。当锁被释放时,头节点的线程会被唤醒尝试获取锁。
条件变量
ReentrantLock
还提供了条件变量(Condition),它类似于 Object 类中的 wait()
和 notify()
方法。条件变量提供了一种在某个条件不满足时挂起线程,并在条件可能满足时唤醒线程的机制。
总结
ReentrantLock
的底层原理主要依赖于 AQS 框架,通过维护一个同步状态和一个线程等待队列来实现锁的获取和释放。它提供了比 synchronized
更灵活的锁操作,包括可重入性、中断锁等待、尝试非阻塞获取锁、公平性选择等特性。通过这些机制,ReentrantLock
在多线程编程中提供了强大的同步控制能力。