15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
王宝令
该思维导图由 AI 生成,仅供参考
在上一篇文章中,我们讲到 Java SDK 并发包里的 Lock 有别于 synchronized 隐式锁的三个特性:能够响应中断、支持超时和非阻塞地获取锁。那今天我们接着再来详细聊聊 Java SDK 并发包里的 Condition,Condition 实现了管程模型里面的条件变量。
在很多并发场景下,支持多个条件变量能够让我们的并发程序可读性更好,实现起来也更容易。例如,实现一个阻塞队列,就需要两个条件变量。
那如何利用两个条件变量快速实现阻塞队列呢?
一个阻塞队列,需要两个条件变量,一个是队列不空(空队列不允许出队),另一个是队列不满(队列已满不允许入队),这个例子我们前面在介绍管程的时候详细说过,这里就不再赘述。相关的代码,我这里重新列了出来,你可以温故知新一下。
不过,这里你需要注意,Lock 和 Condition 实现的管程,线程等待和通知需要调用 await()、signal()、signalAll(),它们的语义和 wait()、notify()、notifyAll() 是相同的。但是不一样的是,Lock&Condition 实现的管程里只能使用前面的 await()、signal()、signalAll(),而后面的 wait()、notify()、notifyAll() 只有在 synchronized 实现的管程里才能使用。如果一不小心在 Lock&Condition 实现的管程里调用了 wait()、notify()、notifyAll(),那程序可就彻底玩儿完了。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
Dubbo中异步转同步的实现原理是通过使用管程模型中的Lock和Condition来实现的。文章首先介绍了Java SDK并发包中的Lock和Condition,以及它们相对于synchronized的灵活性和丰富功能。通过详细讲解阻塞队列的实现,强调了Lock和Condition的特点和使用方法。接着,文章引入了同步与异步的概念,并解释了Dubbo中异步转同步的原理。通过分析Dubbo源码,重点讲解了DefaultFuture类的实现,展示了其使用Lock和Condition实现的管程模型来实现异步转同步的功能。最后,总结了Lock和Condition的灵活性和功能丰富性,强调了理解原理对于快速学好并发编程的重要性。通过实例和源码分析,使读者能够快速了解并掌握Lock和Condition的使用方法以及Dubbo中异步转同步的实现原理。文章内容深入浅出,对于想要深入理解并发编程的读者具有很高的参考价值。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》,新⼈⾸单¥59
《Java 并发编程实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(104)
- 最新
- 精选
- ZOU志伟不合理,会导致很多请求超时,看了源码是调用signalAll()
作者回复: 写这一章的时候还是signal,后来有人提了个bug,就改成signalall了
2019-04-0320159 - 张天屹我理解异步的本质是利用多线程提升性能,异步一定是基于一个新开的线程,从调用线程来看是异步的,但是从新开的那个线程来看,正是同步(等待)的,只是对于调用方而言这种同步是透明的。正所谓生活哪有什么岁月静好,只是有人替你负重前行。
作者回复: 总结的太有文采了!异步加上非阻塞IO才有威力
2019-04-0413110 - 右耳听海in the method of org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived, I think we should call done.signalAll() instead of done.signal() ,and it's unnecessary to check done != null because it's always true
作者回复: 留言这两点有同学都提到了。我表示震撼!
2019-04-2850 - Geek_e6f3ec老师关于dubbo源码的执行流程有一点疑问。 以下是源码 // 调用通过该方法等待结果 Object get(int timeout){ long start = System.nanoTime(); lock.lock(); try{ while (!isDone()){ done.wait(timeout); // 在这里调用了等待方法后面的代码还能执行吗? 我理解的管程,是在条件变量等待队列中阻塞等待,被唤醒之后也不是马上执行也要去管程入口等待队列,也就是lock.lock处等待获取锁。 老师是这样的吗? long cur = System.nanoTime(); if (isDone()||cur-start> timeout){ break; } } }finally { lock.unlock(); } return returnFromResponse(); }
作者回复: 会去获取锁,但是获取锁后,会执行wait后的代码
2019-05-15420 - 木刻老师今天提到异步转同步,让我想到这两天看的zookeeper客户端源码,感觉应该也是这个机制,客户端同步模式下发送请求后会执行packet.wait,收到服务端响应后执行packet.notifyAll
作者回复: 👍
2019-04-0217 - 苏格拉底23老师您好! 有一个基本的问题不明白,如果每个request对应一个线程,似乎并没有用到共享的资源,那么为什么要加锁呢?
作者回复: 这里只是利用管程实现线程的阻塞和唤醒
2019-06-23214 - ban老师,求指教 DefaultFuturewhile这个类为什么要加 while(!isDone()) 这个条件,我看代码while里面加了done.await(timeout);是支持超时的,就是说设置5秒超时, if (isDone() || cur-start > timeout){,只要超过没有被signal()唤醒,那5秒就会自动唤醒,这时候就会在if (isDone() || cur-start > timeout){ 被校验通过,从而break,退出。这时候在加个while条件是不是没必要。 还是说加个while条件是因为时间到点的时候自动唤醒后,Response可能是空,而且时间cur-start > timeout 不超时,所以才有必要进行while再一次判断isDone()是否有值。
作者回复: while条件是编程范式,可以回去看管程原理,搞工程要多重防护。超时后当然很有可能resp是空的
2019-04-038 - 水目沾这是一对一的关系,肯定只需要 signal。每个线程都是相互独立的,lock 和 condition 也是各自独享的。
作者回复: 一对一的关系用signalall也不是不可以
2019-04-026 - ycfHH作为一个完全不懂dubbo的新人,我很好奇是什么bug能让signal改成signalAll,因为不管怎么看都感觉signal就已经可以了啊(虽然使用signalall也不错)
作者回复: 优化而已
2019-05-0635 - 7老师,有个疑问 为什么要判断done!=null呢?这个条件不是永远为true吗。
作者回复: 最新的代码他们已经改过来了😃
2019-04-035
收起评论