博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
可重入锁ReentrantLock解析
阅读量:6403 次
发布时间:2019-06-23

本文共 9298 字,大约阅读时间需要 30 分钟。

说到可重入锁,先从AQS的ConditionObject说起,AQS的内部类ConditionObject是构建显示锁条件队列的基础。之前AQS的没有说这个内部类,这里和ReentrantLock一起说一下。

1、AQS的内部类ConditionObject

addConditionWaiter方法的代码:

这个方法的作用是将当前线程封装好放到条件队列。

1     private Node addConditionWaiter() { 2             Node t = lastWaiter; 3             // If lastWaiter is cancelled, clean out. 4             if (t != null && t.waitStatus != Node.CONDITION) {//如果等待队列的最后一个是取消状态,就把遍历整个队列把所有取消状态的节点清除 5                 unlinkCancelledWaiters(); 6                 t = lastWaiter; 7             } 8             Node node = new Node(Thread.currentThread(), Node.CONDITION);//以当前线程新建一个节点 9             if (t == null)//根据条件将节点放入队列10                 firstWaiter = node;11             else12                 t.nextWaiter = node;13             lastWaiter = node;14             return node;//返回当前线程的节点15         }

doSignal方法的代码:

这个方法的作用就是唤醒当前线程。

1         private void doSignal(Node first) {2             do {3                 if ( (firstWaiter = first.nextWaiter) == null)4                     lastWaiter = null;5                 first.nextWaiter = null;6             } while (!transferForSignal(first) &&//调用了transferForSignal方法7                      (first = firstWaiter) != null);8         }

transferForSignal方法的代码:

1     final boolean transferForSignal(Node node) { 2         /* 3          * If cannot change waitStatus, the node has been cancelled. 4          */ 5         if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))//cas修改值,如果成功等待到了条件成立;如果失败节点的状态改为了CANCELLED,直接返回 6             return false; 7  8         /* 9          * Splice onto queue and try to set waitStatus of predecessor to10          * indicate that thread is (probably) waiting. If cancelled or11          * attempt to set waitStatus fails, wake up to resync (in which12          * case the waitStatus can be transiently and harmlessly wrong).13          */14         Node p = enq(node);//节点入队 这里可能会有点晕,这个节点不是刚从队列里取出吗,怎么又入队了 其实是因为队列不是同一个,每个ConditionObject对象都有一个条件队列,队列里的节点等待的条件成立了会被添加到AQS的队列,这时节点(线程)才有资格等待获取资源15         int ws = p.waitStatus;16         if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//唤醒线程17             LockSupport.unpark(node.thread);18         return true;19     }

doSignalAll方法的代码:

这个方法的作用就是唤醒所有节点(线程)。

1         private void doSignalAll(Node first) {2             lastWaiter = firstWaiter = null;3             do {4                 Node next = first.nextWaiter;5                 first.nextWaiter = null;6                 transferForSignal(first);7                 first = next;8             } while (first != null);9         }

unlinkCancelledWaiters方法的代码:

这个方法被上面说的addConditionWaiter方法调用,将队列的取消状态的节点(线程)清除。

1         private void unlinkCancelledWaiters() { 2             Node t = firstWaiter; 3             Node trail = null; 4             while (t != null) { 5                 Node next = t.nextWaiter; 6                 if (t.waitStatus != Node.CONDITION) { 7                     t.nextWaiter = null; 8                     if (trail == null) 9                         firstWaiter = next;10                     else11                         trail.nextWaiter = next;12                     if (next == null)13                         lastWaiter = trail;14                 }15                 else16                     trail = t;17                 t = next;18             }19         }

doSignal方法的代码:

1         public final void signal() {//唤醒一个节点(线程)2             if (!isHeldExclusively())3                 throw new IllegalMonitorStateException();4             Node first = firstWaiter;5             if (first != null)6                 doSignal(first);7         }

doSignalAll方法的代码:

1         public final void signalAll() {//唤醒所有节点2             if (!isHeldExclusively())3                 throw new IllegalMonitorStateException();4             Node first = firstWaiter;5             if (first != null)6                 doSignalAll(first);7         }

awaitUninterruptibly方法的代码:

这个方法的作用就是将节点(线程)放入条件队列。

1         public final void awaitUninterruptibly() { 2             Node node = addConditionWaiter();//放入条件队列 3             int savedState = fullyRelease(node);//释放资源 4             boolean interrupted = false; 5             while (!isOnSyncQueue(node)) {//当前节点是否在同步队列(在条件队列被唤醒后进入) 6                 LockSupport.park(this);//如果不在,等待 7                 if (Thread.interrupted())//检查是被中断还是被唤醒 8                     interrupted = true;//如果是被中断设置interrupted,下面会设置中断标志 9             }10             if (acquireQueued(node, savedState) || interrupted)//尝试获取资源 设置中断标志11                 selfInterrupt();12         }

await方法的代码:

await方法和awaitUninterruptibly方法很相似,不同的地方是中断的处理。await方法的节点()线程如果是中断结束等待的,会根据当前中断的处理模式判断是抛出异常还是保留中断标志,不会再尝试获取资源。

1         public final void await() throws InterruptedException { 2             if (Thread.interrupted()) 3                 throw new InterruptedException(); 4             Node node = addConditionWaiter(); 5             int savedState = fullyRelease(node); 6             int interruptMode = 0; 7             while (!isOnSyncQueue(node)) { 8                 LockSupport.park(this); 9                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//如果是中断,break10                     break;11             }12             if (acquireQueued(node, savedState) && interruptMode != THROW_IE)13                 interruptMode = REINTERRUPT;14             if (node.nextWaiter != null) // clean up if cancelled15                 unlinkCancelledWaiters();16             if (interruptMode != 0)17                 reportInterruptAfterWait(interruptMode);//抛出异常或保留中断标志18         }

 ConditionObject的代码先说到这,下面说说ReentrantLock的代码。

2、ReentrantLock

ReentrantLock是独占模式的AQS,ReentrantLock有三个内部类,一个是抽象内部类。三个内部类为Sync、NonfairSync和FairSync。后面两个继承自前面一个。下面先说说这三个内部类。

Sync:

nonfairTryAcquire方法:

该方法的作用就是非公平地获取资源。

1         final boolean nonfairTryAcquire(int acquires) { 2             final Thread current = Thread.currentThread(); 3             int c = getState(); 4             if (c == 0) {//如果没有线程占有资源 5                 if (compareAndSetState(0, acquires)) {//如果cas获取资源成功 6                     setExclusiveOwnerThread(current);//将当前线程设置为独占资源的线程 7                     return true; 8                 } 9             }10             else if (current == getExclusiveOwnerThread()) {//如果当前线程是占有资源的线程11                 int nextc = c + acquires;//增加state ReentrantLock里acquires都传1 state为n说明当前线程重入的次数为n - 112                 if (nextc < 0)//溢出13                     throw new Error("Maximum lock count exceeded");14                 setState(nextc);//设置state值15                 return true;16             }17             return false;18         }

tryRelease方法:

该方法的作用就是释放资源(锁),如果资源值(state)为0,则说明调用unlock的次数和调用lock的次数一样,锁可以释放供其它线程获取。

1         protected final boolean tryRelease(int releases) { 2             int c = getState() - releases; 3             if (Thread.currentThread() != getExclusiveOwnerThread())//如果当前线程不是独占占有资源的线程 4                 throw new IllegalMonitorStateException();//抛出异常 5             boolean free = false; 6             if (c == 0) {//如果c等于0 资源全部释放(也就是释放了锁) 7                 free = true; 8                 setExclusiveOwnerThread(null); 9             }10             setState(c);//设置state的值11             return free;//返回是否释放了锁12         }

newCondition方法:

该方法的作用就是创建新的条件队列。

1         final ConditionObject newCondition() {2             return new ConditionObject();3         }

NonfairSync:

lock方法:

非公平获取锁,每个线程获取锁时都会先cas试一下,如果成功了就直接获取了锁,不用再从入队出队开始。

1         final void lock() {2             if (compareAndSetState(0, 1))3                 setExclusiveOwnerThread(Thread.currentThread());4             else5                 acquire(1);//如果不成功还要排队继续6         }

tryAcquire方法:

1         protected final boolean tryAcquire(int acquires) {2             return nonfairTryAcquire(acquires);3         }

FairSync:

lock方法:

公平获取锁,直接调用acquire,从入队出队开始。

final void lock() {            acquire(1);        }

tryAcquire方法:

tryAcquire方法和nonfairTryAcquire方法类似,主要区别在于tryAcquire要求获取资源的节点(线程)必须是队首节点。

protected final boolean tryAcquire(int acquires) {            final Thread current = Thread.currentThread();            int c = getState();            if (c == 0) {                if (!hasQueuedPredecessors() &&                    compareAndSetState(0, acquires)) {//如果没有前驱节点(线程)且cas设置state成功,当前节点(线程)独占占有锁                    setExclusiveOwnerThread(current);                    return true;                }            }            else if (current == getExclusiveOwnerThread()) {                int nextc = c + acquires;                if (nextc < 0)                    throw new Error("Maximum lock count exceeded");                setState(nextc);                return true;            }            return false;        }

说完了内部类,再看看几个提供的方法。

1     public ReentrantLock() { 2         sync = new NonfairSync(); 3     } 4  5     public ReentrantLock(boolean fair) { 6         sync = fair ? new FairSync() : new NonfairSync(); 7     } 8  9     public void lock() {10         sync.lock();11     }12 13     public void lockInterruptibly() throws InterruptedException {14         sync.acquireInterruptibly(1);15     }16 17     public boolean tryLock() {18         return sync.nonfairTryAcquire(1);19     }20 21     public Condition newCondition() {22         return sync.newCondition();23     }

会发现这些方法基本上都是直接调用上面或之前说的那些方法。

转载于:https://www.cnblogs.com/gouden/p/9203605.html

你可能感兴趣的文章
ECMAScript7规范中的instanceof操作符
查看>>
Hadoop HDFS原理分析
查看>>
【webpack4】基本配置和入门api
查看>>
Mac使用ssh公钥登录Linux
查看>>
【366天】跃迁之路——程序员高效学习方法论探索系列(实验阶段124-2018.02.06)...
查看>>
POJ3070-Fibonacci(矩阵快速幂)
查看>>
[vue插件]基于vue2.x的电商图片放大镜插件
查看>>
标准的组件结构
查看>>
vue——一个页面实现音乐播放器
查看>>
SVG 扬帆起航
查看>>
NET Core-学习笔记(二)
查看>>
职业生涯上的点点滴滴
查看>>
Linux下添加新硬盘,分区及挂载
查看>>
一起来将vscode变成私人定制笔记本
查看>>
Flutter 云音乐
查看>>
RecyclerView实现多type页面
查看>>
个人的web商城网站
查看>>
debian fcitx
查看>>
排中律与实无穷问题的性质分析
查看>>
08/23 学习总结
查看>>