Java Concurrencyパッケージを使用した友人は、実際には、Future自体が広く使用されている同時設計モデルであり、データフローの同期を必要とする同時アプリケーションの開発を大幅に簡素化できます。将来は、一部のドメイン言語(Alice MLなど)で構文レベルでも直接サポートされています。
ここでは、java.util.concurrent.futureを例として、将来の特定の作業方法について簡単に説明します。将来のオブジェクト自体は、非同期処理の結果への参照である明示的な参照と見なすことができます。その非同期性のため、それが参照するオブジェクトは、作成の開始時に利用できない場合があります(たとえば、それはまだ動作中、ネットワーク伝送、または待機中です)。現時点では、将来のプログラムのフローが将来に基づいて参照されるオブジェクトを急いでいない場合、プロセスが将来的に参照する必要があるオブジェクトに行くことができます。 2つの状況になります:
このオブジェクトが利用可能になり、関連するフォローアッププロセスを完了したいと考えています。本当に利用できない場合は、他のブランチプロセスを入力することもできます。
「あなたがいなければ、私の人生はその意味を失うので、たとえ海がなくなったとしても、私はあなたを待っています。 -時間)
前者の場合、参照オブジェクトがfuture.isdone()を呼び出しているかどうかを判断し、後者の場合はget()を呼び出す必要があります。
Get(Long Timeout、TimeUnitユニット)は、同期ブロッキングによってオブジェクトの準備ができているのを待ちます。実際のランタイムがブロックされるか返されるかは、get()の呼び出し時間とオブジェクトの順序に依存します。
簡単に言えば、将来のモードは、継続的なプロセスでのデータ駆動型の並行性のニーズを満たすことができます。同時実行のパフォーマンスの改善を得るだけでなく、継続的なプロセスのシンプルさと優雅さも得ることができます。
他の同時設計パターンとの比較
将来に加えて、他の一般的な並行性設計パターンには、「コールバック駆動型(マルチスレッド環境)」、「メッセージ/イベント駆動型(アクターモデル)」などが含まれます。
コールバックは、即時性が高く、シンプルなインターフェイス設計を備えた最も一般的な非同期性同時性モードです。しかし、将来と比較して、その欠点も非常に明白です。第一に、マルチスレッド環境のコールバックは、一般にコールバックをトリガーするモジュールスレッドで実行されます。つまり、コールバックメソッドのプロバイダーはこのモジュールのスレッドにあります。ユーザーアプリケーションのコールバックも実行します。これは、どのくらいの時間がかかるか、どの例外が発生するかを判断できないため、このモジュールの即時性と信頼性に間接的に影響する可能性がありますシーケンスの開発。コールバックメソッドの実行は分離されているため、通常のプロセスとマージすることは困難です。したがって、コールバックインターフェイスは、コールバックで簡単なタスクのみを完了する必要があり、他のプロセスと組み合わせる必要がないシナリオに適しています。
上記のコールバックモードの欠点は、まさに将来の強みです。未来の使用は、非同期データドライバーをシーケンシャルプロセスに組み込むことであるため、スレッドミューテックスの問題をまったく検討する必要はありません。以下に「怠zyな未来」)を参照してください。一方、将来のインターフェイスを提供するモジュールは、コールバックインターフェイスやこのモジュールへの潜在的な即時性の影響などの信頼性の問題を心配する必要はありません。
別の一般的な同時設計パターンは「メッセージ(イベント)駆動型」です。これは一般にアクターモデルで使用されます。サービスリクエスターはサービスプロバイダーにメッセージを送信し、サービス処理結果に依存しない後続のタスクを実行し続けます。 、そして、それに依存している場合は、結果に依存する必要があります。この状態マシンベースの同時制御は、コールバックよりも連続性の連続プロセスにより適していますが、開発者は非同期サービスの呼び出しに従って、継続的なプロセスを複数の状態固有のサブプロセスに削減する必要があります。将来のモードを使用すると、この問題を回避でき、非同期呼び出しの連続プロセスを破る必要はありません。ただし、1つに注意する必要があります。Future.get()メソッドはスレッドの実行をブロックする可能性があるため、通常、従来のアクターモデルに直接組み込むことはできません。 (コルーチンベースの俳優モデルは、この紛争をよりよく解決できます)
Futureの柔軟性は、同期と非同期選択の自由な選択にも反映されています。プロセスのニーズ。たとえば、このギャップを使用して、データの準備が整っているかどうかに基づいて他のタスクを完了するかどうかを決定できます。これは、「非同期分岐予測」メカニズムを実装するのに非常に便利です。
未来の派生物
上記の基本的な形式に加えて、Futureには豊富な派生的な変更もあります。そのため、いくつかの一般的な変化があります。
怠zyな未来
一般的な先物とは異なり、Lazy Futureは作成の開始時に参照されたオブジェクトの準備を積極的に開始しませんが、対応する作業を開始する前にオブジェクトが要求されるまで待ちます。したがって、怠zyな未来自体は同時性を達成することを意図していませんが、不要なコンピューティングリソースを出発点として節約することを目的としており、その効果はラムダ/閉鎖に似ています。たとえば、特定のAPIを設計する場合、情報のセットを返す必要があり、それらの一部の計算ではかなりのリソースが消費される場合があります。ただし、発信者はこのすべての情報を心配していない可能性があるため、怠zyな未来の形でより多くのリソースを必要とするオブジェクトを提供すると、発信者が特定の情報を使用する必要がない場合にリソースを節約できます。
さらに、怠zyな未来を使用して、早期の獲得またはリソースのロックによって引き起こされる不必要な相互除外を回避することもできます。
約束
約束は、将来の特別な枝と見なすことができます。一般的に、サービスコールナーは、サービスを呼び出すときや怠zyな将来の価値が取られたときに処理をトリガーするなど、非同期処理プロセスに直接連絡することによって引き起こされます。しかし、約束は、非同期プロセスがサービス発信者によって直接トリガーされないシナリオを明示的に表すために使用されます。たとえば、将来のインターフェースのタイミング制御では、発信者によってトリガーされませんが、たとえば、Taobaoの分散サブスクリプションフレームワークによって提供される将来のサブスクリプションインターフェイスは、待機中のデータの可用性によって決定されません。サブスクライバーですが、出版社はいつデータを公開または更新しますか。したがって、標準の将来と比較して、Promiseインターフェイスには一般に、追加のset()またはfulfill()インターフェイスがあります。
再利用可能な未来
通常の将来は1回限りです。つまり、非同期処理結果を取得すると、将来のオブジェクト自体がその意味を失うことを意味します。しかし、特別に設計された未来も再利用することができます。これは、複数回変更できるデータに非常に役立ちます。たとえば、上記のTAOBAO分散サブスクリプションフレームワークによって提供される将来のスタイルのインターフェイスは、waitnext()メソッド(future.get()に相当するかどうか)に複数の呼び出しを許可します。最後のデータリリースがまだありません。この設計の利点は、インターフェイスのユーザーが、適切な時間にサブスクリプションデータの変更に応答したり、単に独立したスレッドで無限のループを介して応答しながら、他のタイミングタスクを考慮したり、複数のタスクを待ったりすることもできることです。同時に。簡素化された例は次のとおりです。
for(;;){schedule = getnextscheduledtasktime(); 。}} doscheduledtask();}未来の使用
まず、Javaで考えているコードをリストしましょう。
//:concurrency/callablemo.javaimport java.util.concurrent。*; Import java.util。*; string call(){return "task withresult" + id; public static void main(string [] args){executorservice ec = executors.newcachedthreadpool(); new ArrayList <Future <String >>();試す : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: ::::::::::::::::::::::::::::::::::::::::::::完了するまでget()ブロック:system.out.println(fs.get())) ;} catch(ex) :タスクの結果の結果、タスクとタスクの記録の記録の結果、タスクとタスクの記録の2resのUltのultは、タスクとタスクとタスクの解釈のresult of task withResult 7result of taskwithResult 8result of taskwithreult 9*///:〜Futureの使用を説明するために、最初に、executorserviceオブジェクトExec Call()メソッドを呼び出して将来のオブジェクトを生成します。 ISDONE()メソッドを使用して、将来が完了したかどうかを照会できます。タスクが完了すると、結果が得られ、get()メソッドを呼び出して結果を取得できます。 ISDONE()チェックなしでget()を直接呼び出すこともできます。 get()関数をタイムアウトで呼び出すか、最初にisdone()を呼び出して、タスクが完了したかどうかを確認し、次にget()を呼び出します。