[解決済み] Javaエグゼキュータ:タスクの完了をブロックせずに通知する方法とは?
質問
私はエグゼキュータサービスに提出する必要があるタスクでいっぱいのキューを持っているとします。 私はそれらを一度に一つずつ処理したい。 私が考える最も簡単な方法は、次のとおりです。
- キューからタスクを取り出す
- エグゼキュータに提出する
- 返されたFutureに対して.getを呼び、結果が得られるまでブロックする。
- キューから別のタスクを取る...
しかし、私はブロッキングを完全に避けようとしています。 このようなキューが1万個もあって、それらが一度に1つずつタスクを処理する必要がある場合、そのほとんどがブロックされたスレッドを保持することになるので、スタックスペースが足りなくなるのです。
私が望むのは、タスクを送信して、タスクが完了したときに呼び出されるコールバックを提供することです。 そのコールバックの通知を、次のタスクを送るためのフラグとして使うのです。(functionaljavaとjetlangはそのようなノンブロッキングアルゴリズムを使用しているようですが、私は彼らのコードを理解することができません)
JDKのjava.util.concurrentを使ってそれを実現するには、独自のエグゼキューターサービスを書く以外に方法はないのでしょうか?
(これらのタスクを送り出すキュー自体がブロックされる可能性がありますが、それは後で取り組むべき問題です)
解決方法は?
完了通知で渡したいパラメータを受け取るコールバックインターフェースを定義する。そして、タスクの終了時にそれを呼び出します。
Runnableタスクの一般的なラッパーを書き、それらを
ExecutorService
. または、Java 8に組み込まれたメカニズムについては、以下を参照してください。
class CallbackTask implements Runnable {
private final Runnable task;
private final Callback callback;
CallbackTask(Runnable task, Callback callback) {
this.task = task;
this.callback = callback;
}
public void run() {
task.run();
callback.complete();
}
}
と
CompletableFuture
Java 8 では、非同期かつ条件付きで処理を完了させることができるパイプラインを構成するための、より精巧な手段が提供されています。以下は、通知のための巧妙な、しかし完全な例です。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class GetTaskNotificationWithoutBlocking {
public static void main(String... argv) throws Exception {
ExampleService svc = new ExampleService();
GetTaskNotificationWithoutBlocking listener = new GetTaskNotificationWithoutBlocking();
CompletableFuture<String> f = CompletableFuture.supplyAsync(svc::work);
f.thenAccept(listener::notify);
System.out.println("Exiting main()");
}
void notify(String msg) {
System.out.println("Received message: " + msg);
}
}
class ExampleService {
String work() {
sleep(7000, TimeUnit.MILLISECONDS); /* Pretend to be busy... */
char[] str = new char[5];
ThreadLocalRandom current = ThreadLocalRandom.current();
for (int idx = 0; idx < str.length; ++idx)
str[idx] = (char) ('A' + current.nextInt(26));
String msg = new String(str);
System.out.println("Generated message: " + msg);
return msg;
}
public static void sleep(long average, TimeUnit unit) {
String name = Thread.currentThread().getName();
long timeout = Math.min(exponential(average), Math.multiplyExact(10, average));
System.out.printf("%s sleeping %d %s...%n", name, timeout, unit);
try {
unit.sleep(timeout);
System.out.println(name + " awoke.");
} catch (InterruptedException abort) {
Thread.currentThread().interrupt();
System.out.println(name + " interrupted.");
}
}
public static long exponential(long avg) {
return (long) (avg * -Math.log(1 - ThreadLocalRandom.current().nextDouble()));
}
}
関連
-
プロジェクトの依存関係を解決できなかった 解決
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] Java Mapの各エントリを効率的に反復処理するには?
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] JavaでArrayListではなくLinkedListを使用するのはいつですか?
-
[解決済み] JavaでStringをintに変換するにはどうしたらいいですか?
-
[解決済み] Javaで配列に特定の値が含まれているかどうかを判断するにはどうすればよいですか?
-
[解決済み] Java で、あるコンストラクタを別のコンストラクタから呼び出すにはどうすればよいですか?
-
[解決済み] Javaで配列を宣言し、初期化する方法は?
-
[解決済み] Javaで文字列値からenum値を取得する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
java の例外が発生しました java
-
jd-gui Java Exceptionが発生しました。
-
Intellij IDEAのエラー「CreateProcess error=2, system could not find specified file」に対する完璧な解決策です。
-
サーブレットクラスのインスタンス化エラーの解決法
-
Spring BootのテストメソッドFailed to load ApplicationContextの問題を解決する
-
node js npm gruntインストール、elasticsearch-head 5.Xインストール
-
が 'X-Frame-Options' を 'deny' に設定しているため、フレーム内にある。
-
Javaエラーメッセージがenclosingクラスでない
-
[オリジナル】java学習ノート【II】よくあるエラー クラスパス上のクラスファイルが見つからない、またはアクセスできない場合
-
スレッド "main" で例外発生 java.net.BindException: アドレスは既に使用中です。NET_Bind