Lock底层原理

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

全网最细面试题手册,支持艾宾浩斯记忆法。这是一份最全面、最详细、最高质量的 java面试题,不建议你死记硬背,只要每天复习一遍,有个大概印象就行了。 https://store.amazingmemo.com/chapterDetail/1685324709017001`

Lock底层原理

在Java中,锁(Lock)是用来控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对它进行操作。Java中的锁分为内置锁(synchronized关键字实现)和显式锁(java.util.concurrent.locks包中的类实现,如ReentrantLock)。这里我们主要讨论显式锁的底层原理。

ReentrantLock

ReentrantLockjava.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在多线程编程中提供了强大的同步控制能力。

最后更新于