admin管理员组文章数量:1599412
Condition与Lock的方法
Condition与Lock是两个接口,以上是它们内部定义的方法。Lock中有一个newCondition方法,所以Condition都是从Lock中创建出来的。
Condition实现原理
以读写锁为例来看原理:
public class ReentrantLock implements Lock, java.io.Serializable {
...
public Condition newCondition() {
return sync.newCondition();
}
}
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
...
public static class ReadLock implements Lock, java.io.Serializable {
...
public Condition newCondition() {
throw new UnsupportedOperationException(); //读锁不支持Condition
}
}
...
public static class WriteLock implements Lock, java.io.Serializable {
...
public Condition newCondition() {
return sync.newCondition();
}
}
}
读写锁中的读锁不支持Condition,而写锁和互斥锁支持Condition。
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer implements java.io.Serializable {
public class ConditionObject implements Condition, java.io.Serializable {
...
private transient Node firstWaiter;// 阻塞队列队头
private transient Node lastWaiter; // 阻塞队列队尾
...
}
}
Sync继承自AQS,AQS有ConditionObject类,ConditionObject内定义了阻塞队列。
Sync类内定义了newCondition()方法得到ConditionObject,而写锁和互斥锁都调用了sync的newCondition()。
final ConditionObject newCondition() {
return new ConditionObject();
}
await()实现
public final void await() throws InterruptedException {
if (Thread.interrupted()) //在执行await()时,收到中断信号,抛出异常
throw new InterruptedException();
Node node = addConditionWaiter(); //往阻塞队列加入线程
int savedState = fullyRelease(node);//在加入队列前先要先释放锁
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this); //阻塞自己
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE) //线程被唤醒后,再次获取锁
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode); // 被中断唤醒时,向外抛出异常
}
//addConditionWaiter()的具体实现,线程在调用await()时,已经先拿到锁了,
//所以,在往队列添加线程时,不用CAS操作
private Node addConditionWaiter() {
Node t = lastWaiter;
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
//checkInterruptWhileWaiting(Node node)的实现
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
}
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { //尝试将线程状态从条件状态设置为同步状态0,成功后将节点加入AQS同步队列尾部
enq(node);
return true;
}
while (!isOnSyncQueue(node)) // 设置失败后,自旋尝试让当前线程的CPU执行时间让出,直到唤醒的节点在AQS同步队列为止
Thread.yield();
return false;
}
线程被唤醒有两种可能,别的线程调用unpark()或者中断唤醒。所以在被重新唤醒后要判断是否是中断唤醒,如果是,则跳出循环,然后抛出异常。而如果是被signal()唤醒的话,线程会被放到同步队列中,同样会跳出循环。
awaitUninterruptibly()的实现
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
与await()的区别在于,收到中断后不会抛出异常,也就是不响应异常。
signal()的实现
public final void signal() {
if (!isHeldExclusively()) // 判断当前线程是否持有锁
throw new IllegalMonitorStateException();
Node first = firstWaiter; //获取第一个等待线程
if (first != null)
doSignal(first);
}
private void doSignal(Node first) { //唤醒第一个等待线程
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) //修改线程状态,从条件等待修改为运行状态0
return false;
Node p = enq(node); //将节点放进同步队列里
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); //唤醒线程
return true;
}
signalAll()的原理与signal()类似,不再分享。
总结:Condition与Lock的关系是Condition是Lock的一部分,可以理解为一个锁Lock对应若干个条件Condition,调用await()时会将当前的线程加入到条件队列中,signal()则是将条件队列中的线程加入到同步队列中。
调用await()的作用相当于sychronized里调用wait(),signal()则相当于notify()。
Lock和synchronized对比:1、synchronized是非公平锁,而ReentrantLock可以指定其公平性。2、Synchronized不能响应中断,而ReentrantLock可以。3、synchronized靠执行嵌套的代码块获取锁和释放锁,ReentrantLock通过调用方法来控制,更加灵活。4、synchronized是JVM实现的,而ReentrantLock是JDK实现的。5、一个ReentrantLock可以绑定多个Condition对象,而synchronized是绑定一个对象。6、新版本 Java 对 synchronized 进行了很多优化,例如自旋锁等,synchronized 与 ReentrantLock 大致相同。
参考资料:《Java并发实现原理:JDK源码剖析》
版权声明:本文标题:Condition与Lock 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1728321476a1153879.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论