これを行うには多くの方法があり、すべてが正確なユース ケースに依存します。しかし、すべての方法 (と私は言います) には共通点が 1 つあります。それは、管理された方法でタスクを終了する必要があるということです。データの不整合やその他の問題が発生する可能性があるため、タスクの実行を単に「即時終了」することはできません。これは通常、フラグなどをチェックすることによって行われThread.isInterrupted()
、実行がキャンセルされることを通知している場合は手動で実行を終了します。カスタム フラグを使用することもできます。
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
class Main {
static final ExecutorService executor = Executors.newCachedThreadPool();
// just dummy stuff to simulate calculation
static void someStuff(AtomicBoolean cancel) {
if (cancel.get()) {
System.out.println("interrupted");
return;
}
System.out.println("doing stuff");
for (int i = 0; i < 100_000_000; i++) {
Math.sqrt(Math.log(i));
}
}
static void someTask(AtomicBoolean cancel) {
someStuff(cancel);
someStuff(cancel);
someStuff(cancel);
}
public static void main(String[] args) {
final Set<CompletableFuture<?>> futures = new HashSet<>();
final AtomicBoolean cancel = new AtomicBoolean();
for (int i = 0; i < 10; i++) {
futures.add(CompletableFuture.supplyAsync(
() -> {someTask(cancel); return null;}, executor
));
}
futures.add(CompletableFuture.supplyAsync(() -> {
try {
throw new RuntimeException("dummy exception");
}
catch (RuntimeException re) {
cancel.set(true);
}
return null;
}));
futures.forEach(cf -> cf.join());
executor.shutdownNow();
}
}
最後のタスクが例外をスローし、フラグcancel
を に設定して処理していることに注意してくださいtrue
。他のすべてのタスクは、定期的にチェックすることでそれを確認します。フラグがそれを示す場合、それらは実行をキャンセルします。例外をスローするタスクをコメントアウトすると、すべてのタスクが正常に終了します。
このアプローチは、使用されるエグゼキュータとは無関係であることに注意してください。