簡體   English   中英

如何使用 executor.execute 和 future.get() 結束任務(使線程超時)(通過上升中斷)而不阻塞主線程

[英]How to end a task(timeout a thread) (by rising interrupt) using executor.execute and future.get() without blocking the main thread

我嘗試在執行器服務中使用未來,它可以在不阻塞主線程的情況下工作。 然而,這最終會創建雙倍數量的線程,這是不可取的。 在下面的代碼中,我能夠在沒有阻塞的情況下使用 future.get() 但我必須創建雙倍數量的線程

 for (int i : array) {
                executor.execute(() -> {
                    Future f = new FutureTask(() -> {
                        Goring goring = new Goring();
    
                        goring.goring(i);
    
                    }, null);
                    Thread thread = new Thread((Runnable) f);
                    thread.start();
    
                    try {
                        f.get(1, TimeUnit.NANOSECONDS);
                    } catch (InterruptedException | ExecutionException | TimeoutException|RuntimeException e) {
                        // TODO Auto-generated catch block
                        // System.out.println(e.getMessage());
                        e.printStackTrace();
                        f.cancel(true);
                    }
    
                });
            }
            
    
        executor.shutdown();
    
        }

通常我會推薦使用ExecutorService.invokeAll ,它允許提交任意數量的超時任務,並在超時到期時取消任何尚未完成的任務。

但是您在評論中聲明您希望能夠在較小的並行組中提交任務,例如一次不超過三個並行運行。

您可以創建具有有限並行度的線程池:

ExecutorService executor = Executors.newFixedThreadPool(3);

這里的挑戰是您希望在任務啟動時開始超時,而不是在提交任務時。 由於提交的任務無法訪問自己的 Future,我將使用SynchronousQueue來等待從提交線程傳遞的 Future:

ScheduledExecutorService cancelScheduler =
    Executors.newSingleThreadScheduledExecutor();

for (int i : array) {
    SynchronousQueue<Runnable> cancelQueue = new SynchronousQueue<>();

    Future<?> task = executor.submit(() -> {
        Runnable canceler = cancelQueue.take();
        cancelScheduler.schedule(canceler, 5, TimeUnit.SECONDS);

        Goring goring = new Goring();
        goring.goring(i);

        return null;
    });

    cancelQueue.put(() -> task.cancel(true));
}

executor.shutdown();
cancelScheduler.shutdown();

顧名思義, Executors.newSingleThreadScheduledExecutor()只使用一個線程進行所有調度,這非常適合您的目的,因為計划任務只調用 Future.cancel,所花費的時間可以忽略不計。

return null; 在任務中,從 lambda 返回一個值使其成為 Callable 而不是 Runnable。 (Runnable 的run方法有一個返回類型void ,所以返回值的存在告訴編譯器這個 lambda 不可能代表一個 Runnable。)這意味着它的簽名隱含地throws Exception ,所以沒有必要捕獲 InterruptedException可能由cancelQueue.take()拋出。

暫無
暫無

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

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