【手写dubbo-5】rpc调用异步转同步

        一般情况下每个service的调用的过程都是同步的,例如在一个service中通过RestTemplate调用一个接口,这样也可以认为是一个远程调用,这种是同步进行的,整个调用的思路如下图。调用线程只需要等待调用结果,并且返回即可。这是一种简单的调用方式。

image-20210512181243977

        但是,在使用netty时,整个调用过程是一个异步的过程,上图那种思路就无法达到预期效果。整个调用过程如下图。结果响应之后,selector不知道将结果交给哪个线程处理。

image-20210512183219800

        解决这种异步转同步的过程比较复杂。因此为了使得之前的内容更好理解,并不曾说明此问题。只是在代码中傻傻的写了两行,休眠,然后等待其结果返回。

 //等待其返回
Thread.sleep (1000L);
Object result = client.getResult ();

        这种方式,是一中愚蠢的方式。在一个高性能的框架中,显然不能通过这种方式实现,难道每个接口的调用都要等1秒才返回吗?

异步转同步解决思路

之前的文章中写到,在每个请求的请求信息中,有一个使用AtomicLong类生成的id。这样思路就很明显了,在请求之后,每个线程只需要等待其对应请求编号id响应的结果就好。

image-20210512181615427

        将所有的等待响应的请求存放在一个Map中,为了这个Map更加高效、线程安全,采用ConcurrentHashMap

        每一个正在等待响应的请求都要有一个唯一的id,因此采用AtomicLong获取id。这个id,只需要在所有等待响应的请求中保证唯一即可。

核心类DefaultFuture

public class DefaultFuture
{
	private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<Long, DefaultFuture> ();
	private final DubboRequest request;
	private final Long reqId;
	//加volatile关键字
	private volatile DubboResponse response;
	public DefaultFuture (DubboRequest request)
	{
		this.request = request;
		this.reqId = request.getMId ();
		FUTURES.put (reqId,this);
	}
	public synchronized Object get()   {
		while (response == null) {
			try
			{
				wait (500l);
				System.out.println ("————请求未响应————"+reqId+request.getMData ());
			}
			catch (InterruptedException e)
			{
				e.printStackTrace ();
			}

		}
		return  response.getMData ();
	}
	public static  void received(DubboResponse response){
		DefaultFuture future = FUTURES.remove(response.getMId ());
		if (future != null)
		{
			future.doReceived (response);
		}
	}
	private  synchronized void doReceived(DubboResponse rsp){
		this.response = rsp;
		notify ();
	}
}

利用wait/notify实现响应之后立即唤醒对应线程。

当channel发送消息之后,创建DefaultFuture对象,并且调用get方法进行等待。

DubboRequest req = new DubboRequest ();
RpcInvocation rpc = this.getRpc(serivceClass,method,args);

req.setMData (rpc);
channel.writeAndFlush (req);
DefaultFuture defaultFuture = new DefaultFuture (req);
//等待其返回
Object result = defaultFuture.get ();
return result;

        此思路,与dubbo中com.alibaba.dubbo.remoting.exchange.support.DefaultFuture实现思路一致,另外为了更方便理解,采用synchronized+wait/notify实现等待通知,对java锁机制更加熟悉的小伙伴可以使用ReentrantLock实现等待通知,锁范围更小,性能更佳。

源码地址:gitee

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁滴水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值