Synchronized与ReentrantLock区别总结
一、前言
ReentrantLock是JDK1.5引入的,它拥有与synchronized相同的并发性和内存语义,并提供了超出synchonized的其他高级功能(例如,中断锁等候、条件变量等),并且使用ReentrantLock比synchronized能获得更好的可伸缩性。
ReentrantLock的实现基于AQS(AbstractQueuedSynchronizer)和LockSupport。
AQS主要利用硬件原语指令(CAS compare-and-swap),来实现轻量级多线程同步机制,并且不会引起CPU上文切换和调度,同时提供内存可见性和原子化更新保证(线程安全的三要素:原子性、可见性、顺序性)。
AQS的本质上是一个同步器/阻塞锁的基础框架,其作用主要是提供加锁、释放锁,并在内部维护一个FIFO等待队列,用于存储由于锁竞争而阻塞的线程。
二、关键代码分析
1.关键字段
AQS使用链表作为队列,使用volatile变量state,作为锁状态标识位。
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
2.ReentrantLock的公平锁与非公平锁
从ReentrantLock的构造子可以看到,ReentrantLock提供两种锁:公平锁和非公平锁,其内部实现了两种同步器NonfairSync、FairSync派生自AQS,主要才采用了模板方法模式,主要重写了AQS的tryAcquire、lock方法,如下图。
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
3.获取锁操作
public void lock() {
sync.lock();
}
由于NonfairSync、FairSync分别实现了lock方法,我们将分别探讨
3.1NonfairSync.lock()分析
(1)通过原子的比较并设置操作,如果成功设置,说明锁是空闲的,当前线程获得锁,并把当前线程设置为锁拥有者;
(2)否则,调用acquire方法;
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
3.1.1acquire方法分析
(1)如果尝试以独占的方式获得锁失败,那么就把当前线程封装为一个Node,加入到等待队列中;如果加入队列成功,接下来检查当前线程的节点是否应该等待(挂起),如果当前线程所处节点的前一节点的等待状态小于0,则通过LockSupport挂起当前线程;无论线程是否被挂起,或者挂起后被激活,都应该返回当前线程的中断状态,如果处于中断状态,需要中断当前线程。
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
3.1.2nonfairTryAcquire分析
(1)如果锁状态空闲(state=0),且通过原子的比较并设置操作,那么当前线程获得锁,并把当前线程设置为锁拥有者;
(2)如果锁状态空闲,且原子的比较并设置操作失败,那么返回false,说明尝试获得锁失败;
(3)否则,检查当前线程与锁拥有者线程是否相等(表示一个线程已经获得该锁,再次要求该锁,这种情况叫可重入锁),如果相等,维护锁状态,并返回true;
(4)如果不是以上情况,说明锁已经被其他的线程持有,直接返回false;
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
3.1.3addWaiter分析
(1)如果tail节点不为null,说明队列不为空,则把新节点加入到tail的后面,返回当前节点,否则进入enq进行处理(2);
(2)如果tail节点为null,说明队列为空,需要建立一个虚拟的头节点,并把封装了当前线程的节点设置为尾节点;另外一种情况的发生,是由于在(1)中的compareAndSetTail可能会出现失败,这里采用for的无限循环,是要保证当前线程能够正确进入等待队列;
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
3.1.4acquire分析
(1)如果当前节点是队列的头结点(如果第一个节点是虚拟节点,那么第二个节点实际上就是头结点了),就尝试在此获取锁tryAcquire(arg)。如果成功就将头结点设置为当前节点(不管第一个结点是否是虚拟节点),返回中断状态。否则进行(2)。
(2)检测当前节点是否应该park()-"挂起的意思",如果应该park()就挂起当前线程并且返回当前线程中断状态。进行操作(1)。
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
3.1.5 shouldParkAfterFailedAcquire分析
(1)如果前一个节点的等待状态waitStatus<0,也就是前面的节点还没有获得到锁,那么返回true,表示当前节点(线程)就应该park()了。否则进行(2)。
(2)如果前一个节点的等待状态waitStatus>0,也就是前一个节点被CANCELLED了,那么就将前一个节点去掉,递归此操作直到所有前一个节点的waitStatus<=0,进行(4)。否则进行(3)。
(3)前一个节点等待状态waitStatus=0,修改前一个节点状态位为SINGAL,表示后面有节点等待你处理,需要根据它的等待状态来决定是否该park()。进行(4)。
(4)返回false,表示线程不应该park()。
注意:一个Node节点可包含以下状态以及模式:
/** waitStatus value to indicate thread has cancelled */ 取消
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */ 信号等待(在AQS中,是通过LockSupport进行线程间信号交互的)
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */ 条件等待
static final int CONDITION = -2;
/** Marker to indicate a node is waiting in shared mode */ 共享模式
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */ 独占模式
static final Node EXCLUSIVE = null;
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
3.2FairSync.lock()分析
公平锁相对与非公平锁,在锁的获取实现上,差别只在FairSync提供自己的tryAcquire()的方法实现,代码如下:
(1)如果锁状态为0,等待队列为空,或者给定的线程在队列的头部,那么该线程获得锁;
(2)如果当前线程与锁持有者线程相等,这种情况属于锁重入,锁状态加上请求数;
(3)以上两种情况都不是,返回false,说明尝试获得锁失败;
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
4.总结
ReentrantLock在采用非公平锁构造时,首先检查锁状态,如果锁可用,直接通过CAS设置成持有状态,且把当前线程设置为锁的拥有者。
如果当前锁已经被持有,那么接下来进行可重入检查,如果可重入,需要为锁状态加上请求数。如果不属于上面两种情况,那么说明锁是被其他线程持有,
当前线程应该放入等待队列。
在放入等待队列的过程中,首先要检查队列是否为空队列,如果为空队列,需要创建虚拟的头节点,然后把对当前线程封装的节点加入到队列尾部。由于设置尾部节点采用了CAS,为了保证尾节点能够设置成功,这里采用了无限循环的方式,直到设置成功为止。
在完成放入等待队列任务后,则需要维护节点的状态,以及及时清除处于Cancel状态的节点,以帮助垃圾收集器及时回收。如果当前节点之前的节点的等待状态小于1,说明当前节点之前的线程处于等待状态(挂起),那么当前节点的线程也应处于等待状态(挂起)。挂起的工作是由LockSupport类支持的,LockSupport通过JNI调用本地操作系统来完成挂起的任务(java中除了废弃的suspend等方法,没有其他的挂起操作)。
在当前等待的线程,被唤起后,检查中断状态,如果处于中断状态,那么需要中断当前线程。
在前面一节中,我们分析了ReentrantLock.lock()方法,接下来我们接着分析ReentrantLock.unlock()方法。
1.ReentrantLock.unlock()分析
(1)首先尝试释放锁,如果要求释放数等于锁状态数,那么将锁状态位清0,清除锁所有者,返回true;否则返回false;
(2)如果(1)返回的是true,说明锁完全释放。接下来将检查等待队列,并选择一个waitStatus处于等待状态的节点下的线程unpark(恢复),选择的依据是从尾节点开始,选取最靠近头节点的等待节点,同时清理队列中线程被取消的节点;
(3)如果(1)返回false,说明锁只是部分释放,当前线程仍旧持有该锁;
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
2
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
3
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
4
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
5
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
6
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
7
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
8
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
9
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
10
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
11
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
12
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
13
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
14
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
15
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
16
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
17
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
18
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
19
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
20
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
21
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
22
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
23
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
24
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
25
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
26
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
27
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
28
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
29
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
30
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
31
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020067-529777590.gif)
32
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
33
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
34
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
35
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
36
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
37
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019656-1793687713.gif)
38
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
39
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
40
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
41
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
42
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
43
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
44
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
45
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
46
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
47
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
48
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
49
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
50
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
51
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020019-185013963.gif)
52
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
53
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
54
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
55
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
56
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020026-1783691941.gif)
57
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
58
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111020068-2036374415.gif)
59
![](https://img2024.cnblogs.com/blog/572188/202402/572188-20240208111019949-459704589.gif)
相似点:
这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。
功能区别:
这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成
便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized
性能的区别:
在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。
1.Synchronized
Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。
-
public class SynDemo{
-
-
public static void main(String[] arg){
-
Runnable t1=new MyThread();
-
new Thread(t1,"t1").start();
-
new Thread(t1,"t2").start();
-
}
-
-
}
-
class MyThread implements Runnable {
-
-
-
public void run() {
-
synchronized (this) {
-
for(int i=0;i<10;i++)
-
System.out.println(Thread.currentThread().getName()+":"+i);
-
}
-
-
}
-
-
}
2.ReentrantLock
由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:
1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。
2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
公平锁、非公平锁的创建方式:
-
//创建一个非公平锁,默认是非公平锁
-
Lock lock = new ReentrantLock();
-
Lock lock = new ReentrantLock(false);
-
-
//创建一个公平锁,构造传参true
-
Lock lock = new ReentrantLock(true);
3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
ReenTrantLock实现的原理:
之后还会总结一篇ReenTrantLock相关的原理底层原理分析,简单来说,ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。
什么情况下使用ReenTrantLock:
答案是,如果你需要实现ReenTrantLock的三个独有功能时。
ReentrantLock的用法如下:
-
public class SynDemo{
-
-
public static void main(String[] arg){
-
Runnable t1=new MyThread();
-
new Thread(t1,"t1").start();
-
new Thread(t1,"t2").start();
-
}
-
-
}
-
class MyThread implements Runnable {
-
-
private Lock lock=new ReentrantLock();
-
public void run() {
-
lock.lock();
-
try{
-
for(int i=0;i<5;i++)
-
System.out.println(Thread.currentThread().getName()+":"+i);
-
}finally{
-
lock.unlock();
-
}
-
}
-
-
}
对ReentrantLock的源码分析这有一篇很好的文章
http://www.blogjava.net/zhanglongsr/articles/356782.html
后续在补充的问题:
Synchronized的原理
ReentrantLock的原理。
ReentrantLock为什么是可重入的。
公平锁和非公平锁是什么?有什么区别。