java 条件 等待_java并发等待条件的实现原理(Condition)

synchronized配合Object的wait()、notify()系列方法可以实现等待/通知模式。

Lock提供了条件Condition,对线程的等待、唤醒操作更加详细和灵活。

Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。

一、Condition实现生产者消费者问题

classBoundedBuffer {final Lock lock = newReentrantLock();//condition 依赖于 lock 来产生

final Condition notFull =lock.newCondition();final Condition notEmpty =lock.newCondition();final Object[] items = new Object[100];intputptr, takeptr, count;//生产

public void put(Object x) throwsInterruptedException {

lock.lock();try{while (count ==items.length)

notFull.await();//队列已满,等待,直到 not full 才能继续生产

items[putptr] =x;if (++putptr == items.length) putptr = 0;++count;

notEmpty.signal();//生产成功,队列已经 not empty 了,发个通知出去

} finally{

lock.unlock();

}

}//消费

public Object take() throwsInterruptedException {

lock.lock();try{while (count == 0)

notEmpty.await();//队列为空,等待,直到队列 not empty,才能继续消费

Object x =items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;

notFull.signal();//被我消费掉一个,队列 not full 了,发个通知出去

returnx;

}finally{

lock.unlock();

}

}

}

二、lock与condition关系

//一个lock可以new多个条件

public static voidmain(String[] args) {

ReentrantLock lock= newReentrantLock();

lock.lock();

Condition newCondition1=lock.newCondition();

newCondition1.await();

newCondition1.signal();

Condition newCondition2=lock.newCondition();

newCondition2.await();

newCondition2.signal();

lock.unlock();

}//ReentrantLock.newCondition()

publicCondition newCondition() {returnsync.newCondition();

}//ReentrantLock.Sync.newCondition()

finalConditionObject newCondition() {return newConditionObject();

}

三、条件队列

每个Condition对象都包含着一个FIFO队列,该队列是Condition对象通知/等待功能的关键。在队列中每一个节点(使用的AQS的节点)都包含着一个线程引用,该线程就是在该Condition对象上等待的线程。

public class ConditionObject implementsCondition, java.io.Serializable {private static final long serialVersionUID = 1173984872572414699L;private transient Node firstWaiter; //头节点

private transient Node lastWaiter; //尾节点

publicConditionObject() {

}/*** 通过addConditionWaiter()方法理解等待队列数据结构

* 将当前线程加入条件等待队列

* 1.Node就是AQS的Node

* 2.单向链表,通过nextWaiter连接

* 3.waitStatus==Node.CONDITION才能在等待队列中*/

privateNode addConditionWaiter() {

Node t=lastWaiter;if (t != null && t.waitStatus !=Node.CONDITION) {

unlinkCancelledWaiters();

t=lastWaiter;

}

Node node= newNode(Thread.currentThread(), Node.CONDITION);if (t == null)

firstWaiter=node;elset.nextWaiter=node;

lastWaiter=node;returnnode;

}/*** 清除队列中不是等待状态的线程*/

private voidunlinkCancelledWaiters() {

Node t=firstWaiter;

Node trail= null; //用于保存前一个节点

while (t != null) {

Node next=t.nextWaiter;if (t.waitStatus !=Node.CONDITION) {

t.nextWaiter= null;if (trail == null)

firstWaiter=next;elsetrail.nextWaiter=next;if (next == null)

lastWaiter=trail;

}elsetrail=t;

t=next;

}

}

}

四、等待await()

public final void await() throwsInterruptedException {if(Thread.interrupted())throw newInterruptedException();

Node node= addConditionWaiter(); //当前线程new Node()加入条件队列

int savedState = fullyRelease(node); //释放当先线程的锁

int interruptMode = 0;/*** 自旋:

* 1.当前节点不在同步队列(刚new的节点肯定不在),挂起当前线程,等待被唤醒

* 2.当其他线程调用同一个ConditionObject的signal方法时,会将队列里的节点放入同步队列,并unpark线程(排队唤醒)

* 3.如果该节点被唤醒,再自旋检查是否在同步队列。发现已经在队列中,就可以跳出循环,获取lock*/

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);

}

五、唤醒signal()

public final voidsignal() {if (!isHeldExclusively()) //检查是否拿到锁

throw newIllegalMonitorStateException();

Node first=firstWaiter;if (first != null)

doSignal(first);

}private voiddoSignal(Node first) {do{if ( (firstWaiter = first.nextWaiter) == null)

lastWaiter= null;

first.nextWaiter= null;

}while (!transferForSignal(first) && //唤醒队列第一个节点

(first = firstWaiter) != null);

}final booleantransferForSignal(Node node) {if (!compareAndSetWaitStatus(node, Node.CONDITION, 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;

}

await() :造成当前线程在接到信号或被中断之前一直处于等待状态。

await(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。

awaitNanos(long nanosTimeout) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。返回值表示剩余时间,如果在nanosTimesout之前唤醒,那么返回值 = nanosTimeout – 消耗时间,如果返回值 <= 0 ,则可以认定它已经超时了。

awaitUninterruptibly() :造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。

awaitUntil(Date deadline) :造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。如果没有到指定时间就被通知,则返回true,否则表示到了指定时间,返回返回false。

signal():唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。

signal()All:唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。

参考资料 / 相关推荐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值