ReentrantLock等待通知机制Condition介绍
Posted sunshine-ground-poems
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock等待通知机制Condition介绍相关的知识,希望对你有一定的参考价值。
Object类中的wait(),notify()和notifyAll()可以实现线程的等待通知模型,同样在ReentrantLock中可以借助Condition来完成这种机制。本篇就简要介绍Condition的工作原理。
先看一下Condition的使用示例:
public class LockConditionTest { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); /** * 等待方法 */ private void startAwait() { try { lock.lock(); System.out.println("开始等待:" + System.currentTimeMillis()); condition.await(); System.out.println("等待结束:" + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } } /** * 释放方法 */ private void startSignal() { try { lock.lock(); System.out.println("开始释放"); condition.signal(); } catch (Exception e) { e.printStackTrace(); }finally { //这里锁被主线程持有,必须释放,让被唤醒的MyThread能够得到锁 lock.unlock(); } } public static void main(String[] args) throws InterruptedException { LockConditionTest test = new LockConditionTest(); MyThread myThread = new LockConditionTest().new MyThread(test); //开始线程。 让线程等待。 myThread.start(); //myThread调用condition.await()释放锁,main线程开始执行 TimeUnit.MILLISECONDS.sleep(1000); //主线程唤醒等待线程 test.startSignal(); } class MyThread extends Thread{ private LockConditionTest test; public MyThread(LockConditionTest test) { this.test = test; } @Override public void run() { //开始等待,释放锁 test.startAwait(); } } }
这段代码的输出为:
开始等待:1550285191899 开始释放 等待结束:1550285192902
等待时间大概为1000毫秒,符合预期。
下面看看Condition的await()方法:
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); // 1 int savedState = fullyRelease(node); // 2 int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); // 3 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); }
主要分为3步:
- 把当前线程封装为一个Node节点,把节点加入等待队列
- fullyRelease()方法,释放锁
- 用LockSupport.park()挂起当前线程
再看看signal()方法:
public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; // 1 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)) // 2 return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); // 3 return true; }
- 从这段代码可以看到,signal()是唤醒等待队列中的第一个线程
- CAS更新节点状态
- 唤醒此节点代表的线程
如果要唤醒全部线程,可以调用signalAll()方法。如果想唤醒部分线程,可以实例化多个Condition配合使用。
以上是关于ReentrantLock等待通知机制Condition介绍的主要内容,如果未能解决你的问题,请参考以下文章