今天小伙伴,拿过来一段代码,说看是同步的一段代码怎么会有异步的效果呢。代码原型是:
他说这段代码我知道能达到异步的效果,但是我不知道是怎么实现的。怎么看都好像有一个线程在等待结果,怎么会有异步效果呢。
我们开发的高并发服务,一般都会有一个工作线程池,用来响应客户端同时发送过来的请求。每个在一个时间点都会独立的处理一件事情。最常见的如下。
ExecutorService
cachedThreadPool=newThreadPoolExecutor(500, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
newSynchronousQueue());
cachedThreadPool.execute(newRunnable() {
@Override
public voidrun() {
//todo list;
});
回调是最常见的异步并发模式,它有即时性高、接口设计简单等。其缺点也非常明显。首先,多线程环境下的回调一般是在触发回调的模块线程中执行的,这就意味着编写回调方法时通常必须考虑线程互斥问题;其次,回调方式接口的提供者在本模块的线程中执行用户应用的回调也是相对不安全的,因为你无法确定它会花费多长时间或出现什么异常,从而可能间接导致本模块的即时性和可靠性受影响;再者,使用回调接口不利于顺序流程的开发,因为回调方法的执行是孤立的,要与正常流程汇合是比较困难的。因此回调接口适合于在回调中只需要完成简单任务,并且不必与其它流程汇合的场景。
事件模式:
一般运用在Actor模型中:服务请求者向服务提供者发送消息,然后继续进行后续不依赖服务处理结果的任务,在需要依赖结果前终止当前流程并记录状态;在等到回应消息后根据记录的状态触发后续流程。这种基于状态机的并发控制虽然比回调更适合于有延续性的顺序流程,但开发者却不得不将连续流程按照异步服务的调用切断为多个按状态区分的子流程,这样又人为的增加了开发的复杂性。
Future:
Boolean response = messageManager.sendSystemMessage(reqArgs);Future> future = RpcContext.getContext().asyncCall(new Callable>() {@Overridepublic Boolean call() throws Exception {
// TODO Auto-generated method stub
return messageManager.sendNewSystemMessage(reqArgs);
}
});
response=future.get();
Future方式的好处,除了可以弥补以上方式的缺点外,还体现灵活在同步和异步的自由取舍,开发者可以根据流程的需要自由决定。上述代码借鉴的是开源RPC框架DUBBO 的Future 设计,其中有是否需要等待Future.isDone(),何时等待Future.get(),等待多久Future.get(timeout)。比如可以根据数据是否就绪而决定要不要借这个空档完成点其它任务,这对于实现“异步分支预测”机制是相当方便的。