今天读到一篇博客,发现对Java异步非阻塞编程概念有些模糊了,趁此整理了一下常用的几种编程方式。
方式一:同步调用
当主线程发起IO操作时,会被阻塞,一直等到数据返回,此时主线程状态是Runnable状态。产生的问题是:主线程在IO等待的过程中,线程资源没有得到充分的利用,对于大量IO场景的业务吞吐量会有一定限制。如下图:
方式二:Future方式异步调用
使用future异步获取结果代码示例如下:
ThreadPoolExecutor executor = new ThreadPoolExecutor(......);
Future<Boolean> future = (Future<Boolean>) executor.submit(new Runnable() {
@Override
public void run() {
// 复杂计算
}
});
boolean result = future.get(1000, TimeUnit.MILLISECONDS);
主线程等待示意图如下,此时主线程在等待时间内需要让出cpu,cpu可以做些其他事情,但主线程仍然阻塞(主线程由Runnable状态变为waiting状态):
上述示意代码返回的Future实例是FutureTask类,类图如下,详细分析可参考FutureTask-get方法。
方式三:Callback回调方式
Callback回调方式可参考示意图如下:
对Callback回调机制简要举个例子如下:
// 回调接口
public interface ICallback {
public void callback(String parameter);
}
// 异步执行的业务
public class CallbackTest {
private ExecutorService threadPool = Executors.newFixedThreadPool(2);
public void doSyncInvoke(ICallback callback) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程任务处理");
// 开始处理业务
String result = "this is process result";
// 执行回调函数
callback.callback(result);
}
});
// 交给线程池执行
threadPool.submit(thread);
threadPool.shutdown();
}
}
// 主函数调用
CallbackTest callbackTest = new CallbackTest();
callbackTest.doSyncInvoke(new ICallback() {
@Override
public void callback(String parameter) {
System.out.println("执行回调函数......");
}
});
/**
*输出:
* 子线程任务处理
* 执行回调函数......
**/
另外,Java8提供了CompletableFuture可使用,使用示例如下:
// 输出:hello world Java
CompletableFuture.supplyAsync(() -> "Hello") // 异步处理,类似上述doSyncInvoke
.thenApply(s -> s + " world ") // 回调函数
.thenApply(String::toLowerCase) // 回调函数
.thenCombine(CompletableFuture.completedFuture("Java"), (s1, s2) -> s1 + s2)
.thenAccept(System.out::println);
另外CompletableFuture的类图如下:
方式四:Java9 Reactive Streams
该种方法不再细述,可参考相关资料。
参考:https://mp.weixin.qq.com/s/AVMN8jyqMXWhE9bRs_e0aQ
欢迎关注微信公众号:方辰的博客