//此处是 Node 的部分属性
static final class Node {//排他锁标识
static final Node EXCLUSIVE =null;//如果带有这个标识,证明是失效了
static final int CANCELLED =1;//具有这个标识,说明后继节点需要被唤醒
static final int SIGNAL =-1;//Node对象存储标识的地方
volatile int waitStatus;//指向上一个节点
volatile Node prev;//指向下一个节点
volatile Node next;//当前Node绑定的线程
volatile Thread thread;//返回前驱节点即上一个节点,如果前驱节点为空,抛出异常
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p ==null)
throw new NullPointerException();
else
return p;}}
/** * 公平锁代码 */
final void lock(){
acquire(1);}/** * 非公平锁代码 */
final void lock(){
if (compareAndSetState(0,1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
初步查看代码发现非公平锁似乎包含公平锁的逻辑,所以我们就从“非公平锁”开始。
非公平锁
final void lock(){//通过 CAS 的方式尝试将 state 从0改为1,
//如果返回 true,代表修改成功,获得锁资源;//如果返回false,代表修改失败,未获取锁资源
if (compareAndSetState(0,1))// 将属性exclusiveOwnerThread设置为当前线程,该属性是AQS的父类提供的
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);}
public final void accquire(int arg){// tryAcquire 再次尝试获取锁资源,如果尝试成功,返回true,尝试失败返回false
if (!tryAcquire(arg)&&// 走到这,代表获取锁资源失败,需要将当前线程封装成一个Node,追加到AQS的队列中
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))// 线程中断
selfInterrupt();}
//AQS中
protected boolean tryAcquire(int arg){//AQS 是基类,具体实现在自己的类中实现,我们去查看“非公平锁”中的实现
throw new UnsupportedOperationException();}//ReentrantLock 中
protected final boolean tryAcquire(int acquires){
return nonfairTryAcquire(acquires);}
final boolean nonfairTryAcquire(int acquires){// 获取当前线程
final Thread current = Thread.currentThread();//获取AQS 的 state
int c = getState();// 如果 state 为0,代表尝试再次获取锁资源
if (c ==0){// 步骤同上:通过 CAS 的方式尝试将 state 从0改为1,
//如果返回 true,代表修改成功,获得锁资源;//如果返回false,代表修改失败,未获取锁资源
if (compareAndSetState(0, acquires)){//设置属性为当前线程
setExclusiveOwnerThread(current);
return true;}}//当前占有锁资源的线程是否是当前线程,如果是则证明是可重入操作
else if (current == getExclusiveOwnerThread()){//将 state +1int nextc = c + acquires;//为什么会小于 0 呢?因为最大值 +1 后会将符号位的0改为1 会变成负数(可参考Integer.MAX_VALUE+1)
if (nextc <0)// overflow
//加1后小于0,超出锁可重入的最大值,抛异常
throw new Error("Maximum lock count exceeded");//设置 state 状态
setState(nextc);
return true;}
return false;}
//释放锁方法
public void unlock(){
sync.release(1);}
public final boolean release(int arg){//尝试释放锁资源,如果释放成功,返回true
if (tryRelease(arg)){
Node h = head;// head 不为空且 head 的 ws 不为0(如果为0,代表后边没有其他线程挂起)
if (h !=null&& h.waitStatus!=0)// AQS的队列中有 node 在排队,并且线程已经挂起
// 需要唤醒被挂起的 Node
unparkSuccessor(h);
return true;}// 代表释放一次没有完全释放
return false;}
protected final boolean tryRelease(int releases){//获取当前锁的状态,先进行减1操作,代表释放一次锁资源 int c = getState()- releases;//如果释放锁的线程不是占用锁的线程,直接抛出异常 if (Thread.currentThread()!= getExclusiveOwnerThread())
throw new IllegalMonitorStateException();boolean free =false;// 如果 c 为0 ,代表锁完全释放了,如果不为0,代表锁之前重入了,一次没释放掉,等待下次再次执行时,再次判断 if (c ==0){// 释放锁标志为 true,代表完全释放了 free =true;// 将占用互斥锁的标识置为 null setExclusiveOwnerThread(null);}// 设置 state 状态 setState(c);
return free;}
// 注意当前的 node 节点是 head 节点
private void unparkSuccessor(Node node){//获取 head 的状态
int ws = node.waitStatus;
if (ws <0)// CAS 将 node 的 ws 设置为0,代表当前 node 接下来会舍弃
compareAndSetWaitStatus(node, ws,0);// 获取头节点的下一个节点
Node s = node.next;// 如果下一个节点为null 或者 下一个节点为失效节点,需要找到离 head 最近的有效node
if (s ==null|| s.waitStatus>0){
s =null;// 从尾节点开始往前找不等于null且不是node的节点
for (Node t = tail; t !=null&& t != node; t = t.prev)// 如果该节点有效,则将s节点指向t节点
if (t.waitStatus<=0)
s = t;}// 找到最近的node后,直接唤醒
if (s !=null)
LockSupport.unpark(s.thread);}
private final boolean parkAndCheckInterrupt(){
LockSupport.park(this);//返回目标线程是否中断的布尔值:中断返回true,不中断返回false,且返回后会重置中断状态为未中断
return Thread.interrupted();}
1.
2.
3.
4.
5.
因为线程2未中断,所以返回false。继续执行acquireQueued()中的死循环
for (;;){// 获取当前节点的上一个节点
final Node p = node.predecessor();//p为头节点,尝试获取锁操作
if (p == head && tryAcquire(arg)){
setHead(node);
p.next=null;// 将获取锁失败标识置为false
failed =false;// 获取到锁资源,不会被中断
return interrupted;}// p 不是 head 或者 没拿到锁资源,
if (shouldParkAfterFailedAcquire(p, node)&&// 基于 Unsafe 的 park方法,挂起线程
parkAndCheckInterrupt())
interrupted =true;}
public final boolean hasQueuedPredecessors(){
Node t = tail;
Node h = head;
Node s;
return h != t &&((s = h.next)==null|| s.thread!= Thread.currentThread());}