ReentrantLock等待通知机制Condition介绍
程序员文章站
2022-05-14 09:42:01
Object类中的wait(),notify()和notifyAll()可以实现线程的等待通知模型,同样在ReentrantLock中可以借助Condition来完成这种机制。本篇就简要介绍Condition的工作原理。 先看一下Condition的使用示例: 这段代码的输出为: 等待时间大概为10 ......
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配合使用。