dubbo系列之网络通信-IO异步变同步
简要
dubbo 是基于netty NIO的非阻塞 并行调用通信。 (阻塞 非阻塞 异步 同步 区别 )
dubbo 的通信方式 有3类类型:
1.异步,有返回值
1 | <dubbo:method name="sayHello" async="true"></dubbo:method> |
2.异步,无返回值
1 | <dubbo:method name="sayHello" return="false"></dubbo:method> |
3.异步,变同步(默认的通信方式)
源码介绍
三种不同通信方式在代码中判断就是在前面一直有提到过的DubboInvoker类
DubboInvoker类
doInvoker()
1 | protected Result doInvoke(final Invocation invocation) throws Throwable { |
那通信方式又是在哪设置的呢?
dubbo-demo-consumer.xml
1 | <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" /> |
原来的配置是这样的,默认就是进去3.异步,变同步。
1:异步,有返回值
1 | <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" > |
启动服务端和客户端
看一下DemoAction类的打印效果
打印的全是null了。
断点进入doInvoke()
1 | else if (isAsync) {//1:异步,有返回值 |
我们修改一下DemoAction的hello打印值
start()
1 | public void start() throws Exception { |
这样打印的结果就不再是null了
2:异步,无返回值
dubbo-demo-consumer.xml
1 | <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" > |
DemoAction类
start()
1 | public void start() throws Exception { |
打印结果就又变null了。
看了前面两种情况,我们大致了解了,由于demoService.sayHello(“world” + i)方法是同步的,所以在正常异步情况下打印这个就是null值,那怎么才能获取这个值呢?接着看第三者情况。
下面就是这篇博客的重点了。
3:异步,变同步
问题:当前线程怎么让它 “暂停,等结果回来后,再执行”?
看代码
DubboInvoker类
1 | else {//3.异步,变同步(默认的通信方式) |
HeaderExchangeChannel类
1 | public ResponseFuture request(Object request, int timeout) throws RemotingException { |
所以DubboInvoker里面是返回的DefaultFuture的get()方法。
DefaultFuture类
get()
1 | private final Condition done = lock.newCondition();//jdk多线程里面的condition |
1 | public boolean isDone() { |
当reponse拿到数据后,isDone()就为true,就会结束死循环。
我们再看一下上一篇博客介绍的consumer接收数据的处理
DefaultFuture类
doReceived
1 | private void doReceived(Response res) { |
所以等结果回来,就唤醒。这样,返回结果就不再是null了。
问题:socket是一个全双工的通信方式,那么在多线程的情况下,如何知道那个返回结果对应原先那条线程的调用?
看源码
DefaultFuture类
1 | public DefaultFuture(Channel channel, Request request, int timeout) { |
Request类
newId()——id初始化
1 | private static long newId() { |
received()
1 | public static void received(Channel channel, Response response) { |
在consumer接收数据时,会将FUTURES中的这条数据删除。
所以上面问题的答案就是——>通过一个全局唯一的ID来做consumer 和 provider 来回传输。
单工 全双工 半双工的区别?
单工:在同一时间只允许一方向另一方传送信息,而另一方不能向一方传送
全双工:是指在发送数据的同时也能够接收数据,两者同步进行,这好像我们平时打电话一样,说话的同时也能够听到对方的声音。目前的网卡一般都支持全双工。
半双工:所谓半双工就是指一个时间段内只有一个动作发生。举个简单例子,一条窄窄的马路,同时只能有一辆车通过,当目前有两量车对开,这种情况下就只能一辆先过,等到头后另一辆再开,这个例子就形象的说明了半双工的原理。