簡體   English   中英

CompletableFuture.get(timeout) 不應該終止任務嗎?

[英]Shouldn't CompletableFuture.get(timeout) kill the task?

我正在運行兩個CompletableFuture實例,它們等待 1 秒並向控制台打印一些內容。 我在 0.5 秒后打斷了第一個。 所以我希望只打印第二個,但實際上兩者都可以。 這里發生了什么?

這是代碼:

CompletableFuture<Void> c1 = CompletableFuture.runAsync(() -> {
    System.out.println("Start CF 1");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.out.println(1);
});

CompletableFuture<Void> c2 = CompletableFuture.runAsync(() -> {
    System.out.println("Start CF 2");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.out.println(2);
});

long start = System.currentTimeMillis();
try {
    c1.get(500, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
    System.out.println("CF interrupted after " + (System.currentTimeMillis() - start) + "ms");
}
c2.get();

它打印:

Start CF 1
Start CF 2
CF interrupted after 510ms
2
1

為什么你認為它應該? 如果 2 個消費者想要處理相同未來的結果,並且一個准備比另一個等待更長的時間怎么辦? 第一個會殺死第二個,它可能會及時完成。

無論如何,Java 沒有殺死任務的概念。 你能做的最好的事情就是設置一個標志要求它停止——一個中斷——但這依賴於任務檢查和尊重標志。 你的任務會,因為Thread.sleep()隱式檢查中斷標志,但這是一個人為的例子,很多任務永遠不會檢查它。

get方法的超時僅說明應該停止執行get方法的時間。 它不影響結果的計算。 這適用於所有期貨。

因此,要中斷任務,您需要調用cancel(true)CompletableFuture的情況下甚至不會中斷任務:

參數:
  • mayInterruptIfRunning - 此值在此實現中沒有影響,因為中斷未用於控制處理。”

如果你想要可中斷的任務,你需要使用ExecutorService ,但你也可以使用與CompletableFuture的默認執行程序相同的線程池:

public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService es = ForkJoinPool.commonPool();
    Future<Void> c1 = es.submit(() -> {
        System.out.println("Start CF 1");
        Thread.sleep(1000);
        System.out.println(1);
        return null;
    });

    Future<Void> c2 = es.submit(() -> {
        System.out.println("Start CF 2");
        Thread.sleep(1000);
        System.out.println(2);
        return null;
    });

    long start = System.currentTimeMillis();
    try {
        c1.get(500, TimeUnit.MILLISECONDS);
    } catch(TimeoutException e) {
        c1.cancel(true);
        System.out.println("timeout after "
                + (System.currentTimeMillis() - start) + "ms, canceled");
    }
    c2.get();
}

請注意,中斷可能仍然太慢,無法阻止1的打印。 在我的機器上,我至少需要Thread.sleep(1100); 在打印前中斷任務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM