忙しい仕事は、この記事を書くための時間を持っていないいくつかの時間前に、この記事では、Java 8は、すでに非ブロック非同期インタフェース(CompletableFuture)を提供して知ったとき、あなたは簡単な反応性プログラミングを達成することができます「Java8の戦闘」を読まれますモードなので、コーマされるように、この記事を使用します。私は、CompletableFutureにこのインタフェースを学ぶために以下の質問をしました
- CompletableFutureは、問題とデザインを解決するには?
- その利用シーンは何ですか?実用的なオープンソースソフトウェアの使用事例は何がありますか?
- CompletableFuture共通APIは何ですか?どのように使用するには?
- CompletableFutureとRxJava違いは何ですか?
この記事では、ダウンくし、基本的にOK、我々はテキストを入力し、最初の4つの質問に答えることができます。
基本コンセプト
RPC(リモートメソッド呼び出し)の4つの方法があります:一方向、同期、将来のコールバックと、ダボボルトや、通信フレームで、デフォルトの同期モード(同期+閉塞)、および今後のコールバックは、非同期モードに属ししかし、将来のモデルを使用して、結果を待つ必要はありません、コールバックモードの時にブロックされます、サーバーは、要求元の結果の後にコールバックします。
このような非同期呼び出しモードは、シーンは、リモート呼び出し、多くのタスクを実行するために、IO集約型のシーンのために、より適しており、これらの呼び出しは、より多くの時間がかかり、長い時間のためであってもよいです。一例として、ケースopenwriteで:私は記事を公開し、あなたはいくつかの異なる記事を書くためのプラットフォームを作成する必要があり、私はこのプロセスがシーケンシャルである必要はありません、この時間は、それが非同期呼び出しパターンに適しています。
GET()呼び出しがブロックされる場合を除き、今後のモードは、のような他の制限がある:、Javaのラムダ式の利点を使用していない非同期呼び出しのシリーズをサポートすることができますが、コードが複雑になり書き出します。
CompletableFuture共通API
CompletableFuture APIを読んで、私は--CompletableFutureはプルバックにこの最も重要な特性を増加させることに加えて、未来にあると認識するようになった、ストリームを高めるための他の機能は、一連の反復のようなビット。
使用CompletableFuture,我们可以像Stream一样使用一部调用,可以处理一些级联的异步调用(类似于Stream里的flatMap)、可以过滤一些无用的异步调用(anyOf、allOf)。
下面这张图是我按照自己的理解,梳理除了CompletableFuture常见的API,阅读的时候需要注意下面几个点:
- 把握几个大的分类:创建CompletableFuture、获取CompletableFuture的执行结果、主动结束CompletableFuture、异步调用任务的组合处理;
- 看着方法多,但是有规律可循,例如apply字样的接口,传入的方法参数都是有返回值的;
- 带either字样的,都是多个异步任务有一个满足条件即可的;
- 带executor方法的,都表示该方法可以用自定义的线程池来优化性能。
Dubbo项目中的使用案例
Dubbo对于异步化的支持起始在2.6.x中就有提供,是在发布bean的时候加个属性配置——async=true,然后利用上下文将异步标识一层层传递下去。在之前的公司中有一次排查dubbo(当时我们用的是dubbox)异步调用的问题,最后查到的原因就是多个异步调用,上下文里的信息串了。
Dubbo 2.7 中使用了 JDK1.8 提供的 CompletableFuture 原生接口对自身的异步化做了改进。CompletableFuture 可以支持 future 和 callback 两种调用方式。在Dubbo最新的master代码中,我知道了Dubbo的异步结果的定义,它的类图如下,可以看出AsyncRpcResult是一个CompletableFuture接口的实现。
实战Demo
通过下面的例子,可以看出CompletableFuture的最大好处——callback特性。首先定义一个接口,其中包括同步接口和该接口的异步版本。
public interface AsyncInterfaceExample {
String computeSomeThine();
CompletableFuture<String> computeSomeThingAsync();
}
然后定义该接口的实现类,可以看出,如果要讲现有的同步接口异步化,是比较容易的;
public class AsyncInterfaceExampleImpl implements AsyncInterfaceExample {
@Override
public String computeSomeThine() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "hello, world";
}
@Override
public CompletableFuture<String> computeSomeThingAsync() {
return CompletableFuture.supplyAsync(this::computeSomeThine);
}
}
然后看下我们的测试case,如下:
public class AsyncInterfaceExampleTest {
private static String getOtherThing() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "other";
}
public static void main(String[] args) {
AsyncInterfaceExample asyncInterfaceExample = new AsyncInterfaceExampleImpl();
//case1 同步调用
long start = System.currentTimeMillis();
String someThing = asyncInterfaceExample.computeSomeThine();
String other = getOtherThing();
System.out.println("cost:" + (System.currentTimeMillis() - start) + " result:" + someThing + other);
//case2 异步调用,使用回调
start = System.currentTimeMillis();
CompletableFuture<String> someThingFuture = asyncInterfaceExample.computeSomeThingAsync();
other = getOtherThing();
long finalStart = start;
String finalOther = other;
someThingFuture.whenComplete((returnValue, exception) -> {
if (exception == null) {
System.out.println(
"cost:" + (System.currentTimeMillis() - finalStart) + " result:" + returnValue + finalOther);
} else {
exception.printStackTrace();
}
});
}
}
以下に示すように、この例の実装の上記の結果、:
***
この数(javaadu)は第一線の開発者を読者に提供するために、バックエンド技術、JVMのトラブルシューティングと最適化、Javaのインタビューの質問、個人の成長と自己管理、および他のトピックに焦点を当て仕事の経験と成長は、あなたはここで何かを得ることを期待することができます。