ReentrantLock等待通知机制Condition介绍
2019-02-17 01:51:51来源:博客园 阅读 ()
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配合使用。
原文链接:https://www.cnblogs.com/sunshine-ground-poems/p/10387181.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:SpringBoot从零到上线
下一篇:Redis
- Java并发编程(04):线程间通信,等待/通知机制 2020-05-16
- 【漫画】互斥锁ReentrantLock不好用?试试读写锁ReadWriteLo 2020-05-15
- 面试被问ReentrantLock的公平锁与非公平锁,区别以及实现 2020-05-12
- Synchronized 与 ReentrantLock 的区别! 2020-04-27
- java 线程间通信 2020-03-31
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash