簡體   English   中英

在 ExecutorService 上調用 shutdown() 的原因

[英]Reason for calling shutdown() on ExecutorService

在過去的幾個小時里,我讀了很多關於它的內容,我根本看不出有任何理由(正當理由)在ExecutorService上調用shutdown() ,除非我們有一個龐大的應用程序來存儲數十個不同的 executor長時間不使用的服務。

關閉所做的唯一一件事(從我收集到的)就是執行正常線程完成后所做的事情。 當普通Thread執行完Runnable(或Callable)的run方法后,會傳遞給Garbage Collection進行回收。 使用 Executor Service 線程將被簡單地擱置,它們不會被垃圾收集勾選。 為此,需要關機。

好的回到我的問題。 是否有任何理由經常在ExecutorService上調用關閉,甚至在向其提交某些任務后立即調用? 我想留下有人正在做的情況,然后在調用awaitTermination()之后awaitTermination()進行驗證。 一旦我們這樣做了,我們必須重新創建一個新的ExecutorService來做同樣的事情。 ExecutorService重用線程的全部想法不是嗎? 那么為什么要這么快銷毀ExecutorService呢?

簡單地創建ExecutorService (或根據您需要的數量而定),然后在應用程序運行期間將任務傳遞給他們,然后在應用程序退出或其他一些重要階段關閉那些執行人?

我想要一些有經驗的編碼人員的答案,他們確實使用 ExecutorServices 編寫了大量異步代碼。

第二個方面的問題,與 android 平台的交易有點小。 如果你們中的一些人會說每次關閉執行程序並不是最好的主意,以及你在 android 上的程序,你能告訴我當我們處理不同的事件時你如何處理這些關閉(具體來說 - 當你執行它們時)應用程序生命周期。

由於 CommonsWare 的評論,我使帖子中立。 我真的沒有興趣把它爭論到死,而且它似乎正在領先。 我只對了解我在這里向有經驗的開發人員詢問的內容感興趣,他們是否願意分享他們的經驗。 謝謝。

shutdown()方法做一件事:阻止客戶端向執行程序服務發送更多工作。 這意味着除非采取其他操作,否則所有現有任務仍將運行完成。 即使對於計划任務也是如此,例如,對於 ScheduledExecutorService:計划任務的新實例不會運行。 它還釋放任何后台線程資源。 這在各種情況下都很有用。

假設您有一個控制台應用程序,它有一個運行 N 個任務的執行程序服務。 如果用戶按下 CTRL-C,您希望應用程序終止,可能會正常終止。 優雅地是什么意思? 也許您希望您的應用程序無法向執行程序服務提交更多任務,同時您希望等待您現有的 N 個任務完成。 您可以使用關閉掛鈎作為最后的手段來實現這一點:

final ExecutorService service = ... // get it somewhere

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Performing some shutdown cleanup...");
        service.shutdown();
        while (true) {
            try {
                System.out.println("Waiting for the service to terminate...");
                if (service.awaitTermination(5, TimeUnit.SECONDS)) {
                    break;
                }
            } catch (InterruptedException e) {
            }
        }
        System.out.println("Done cleaning");
    }
}));

這個鈎子將關閉服務,這將阻止您的應用程序提交新任務,並在關閉 JVM 之前等待所有現有任務完成。 如果服務關閉,等待終止將阻塞 5 秒並返回 true。 這是在循環中完成的,以便您確定服務最終會關閉。 InterruptedException 每次都會被吞下。 這是關閉在整個應用程序中重復使用的執行程序服務的最佳方法。

這段代碼並不完美。 除非您絕對肯定您的任務最終會終止,否則您可能希望等待給定的超時時間,然后退出,放棄正在運行的線程。 在這種情況下,在最后一次嘗試中斷正在運行的線程時在超時后調用shutdownNow()也是有意義的( shutdownNow()還會為您提供等待運行的任務列表)。 如果您的任務旨在響應中斷,這將正常工作。

另一個有趣的場景是當您有一個執行周期性任務的 ScheduledExecutorService 時。 停止周期性任務鏈的唯一方法是調用shutdown()

編輯:我想補充一點,我不建議在一般情況下使用如上所示的關閉鈎子:它可能容易出錯,並且應該只是最后的手段。 此外,如果您注冊了許多關閉掛鈎,則它們運行的​​順序是未定義的,這可能是不可取的。 我寧願讓應用程序在InterruptedException上顯式調用shutdown()

ExecutorService 重用線程的全部想法不是嗎? 那么為什么要這么快銷毀 ExecutorService 呢?

是的。 您不應該頻繁地銷毀和重新創建ExecutorService 在您需要時(主要是在啟動時)初始化ExecutorService並使其保持活動狀態,直到您完成它。

簡單地創建 ExecutorService(或根據您需要的數量而定),然后在應用程序運行期間將任務傳遞給他們,然后在應用程序退出或其他一些重要階段關閉那些執行人?

是的。 在應用程序退出等重要階段關閉ExecutorService是合理的。

第二個方面的問題,與 android 平台的交易有點小。 如果你們中的一些人會說每次關閉執行程序並不是最好的主意,並且你在 android 上編程,你能告訴我當我們處理應用程序的不同事件時你如何處理這些關閉(具體來說,當你執行它們時)生命周期。

假設ExecutorService在您的應用程序中的不同活動之間共享。 每個活動將在不同的時間間隔暫停/恢復,但每個應用程序仍然需要一個ExecutorService

不是在 Activity 生命周期方法中管理ExecutorService的狀態,而是將 ExecutorService 管理(創建/關閉)移動到您的自定義Service

在 Service => onCreate()創建ExecutorService並在onDestroy()正確關閉它

關閉ExecutorService推薦方式:

如何正確關閉java ExecutorService

一旦不再需要 ExecutorService 以釋放系統資源並允許正常關閉應用程序,就應該關閉它。 因為 ExecutorService 中的線程可能是非守護線程,它們可能會阻止正常的應用程序終止。 換句話說,您的應用程序在完成其 main 方法后保持運行。

參考書

第14話頁數:814

在 ExecutorService 上調用 shutdown() 的原因

今天我遇到了一種情況,我必須等到一台機器准備就緒,然后才能在該機器上啟動一系列任務。

我對這台機器進行 REST 調用,如果我沒有收到 503(服務器不可用),那么該機器已准備好處理我的請求。 所以,我等到第一個 REST 調用得到 200(成功)。

有多種方法可以實現它,我使用 ExecutorService 創建一個線程並安排它在每 X 秒后運行一次。 所以,我需要在某個條件下停止這個線程,看看這個......

final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    Runnable task = () -> {
        try {
            int statusCode = restHelper.firstRESTCall();

            if (statusCode == 200) {
                executor.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    };

    int retryAfter = 60;
    executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);

第二個方面的問題,與 android 平台的交易有點小。

如果您提供更多背景信息,也許我可以回答! 此外,根據我在 Android 開發方面的經驗,您很少需要 Threads。 您是否正在開發需要線程以提高性能的游戲或應用程序? 如果沒有,在 Android 中,您有其他方法來解決問題,例如我上面解釋的場景。 您可以根據上下文使用 TimerTask、AsyncTask 或處理程序或加載程序。 這是因為如果 UIThread 等待很長時間你知道會發生什么:/

盡管對於計划的任務,例如,對於 ScheduledExecutorService,這是真實的:預定分配的新案例將不會運行。

我們應該期望你有一個舒適的應用程序,它有一個運行 N 個差事的代理管理。

我沒有毫不費力地抓住它的意思? 也許您需要您的應用程序無法選擇向代理管理部門提交更多任務,同時您需要坐下來完成當前的 N 項任務。

除非你完全肯定你的差事最終會完成,否則你應該需要坐下來休息一段時間,然后簡單地退出,拋棄正在運行的字符串。

如果您的活動旨在對干擾做出反應,這將正常工作。

另一個有趣的情況是您有一個 ScheduledExecutorService 來執行活動。

停止活動鏈的最好方法是調用 shutdown()

暫無
暫無

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

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