簡體   English   中英

即使主要功能退出后,該java程序如何保持運行?

[英]How this java program keeps running even after main function exits?

我正在嘗試學習Java的並發API。 下面是一個示例程序。

    class WaitTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executorService = null;
        try {
            executorService = Executors.newSingleThreadExecutor();
            Future<?> future = executorService.submit(() ->
                {
                    for (int i = 0; i < 100; i++) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("Printing " + i);
                    }
                });
            future.get(5, TimeUnit.SECONDS);
            System.out.println("Reached successfully");
        } finally {
            if (executorService != null) {
                executorService.shutdown();
            }
        }
    }
}

提供給ExecutorService的Runnable任務需要10秒鍾才能完成。 我將超時設置為5秒,以從將來的對象獲取結果。 顯然,由於拋出了TimeoutException,主要方法在5秒后退出。 但是即使主方法退出后,Runnable任務仍繼續執行。

這是輸出。

Printing 0
Printing 1
Printing 2
Printing 3
Printing 4
Printing 5
Printing 6
Printing 7
Printing 8
Printing 9
Printing 10
Printing 11
Printing 12
Printing 13
Printing 14
Printing 15
Printing 16
Printing 17
Printing 18
Printing 19
Printing 20
Printing 21
Printing 22
Printing 23
Printing 24
Printing 25
Printing 26
Printing 27
Printing 28
Printing 29
Printing 30
Printing 31
Printing 32
Printing 33
Printing 34
Printing 35
Printing 36
Printing 37
Printing 38
Printing 39
Printing 40
Printing 41
Printing 42
Printing 43
Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:205)
    at ocp.WaitTest.main(ConcurrencyTest.java:89)
Printing 44
Printing 45
Printing 46
Printing 47
Printing 48
Printing 49
Printing 50
Printing 51
Printing 52
Printing 53
Printing 54
Printing 55
Printing 56
Printing 57
Printing 58
Printing 59
Printing 60
Printing 61
Printing 62
Printing 63
Printing 64
Printing 65
Printing 66
Printing 67
Printing 68
Printing 69
Printing 70
Printing 71
Printing 72
Printing 73
Printing 74
Printing 75
Printing 76
Printing 77
Printing 78
Printing 79
Printing 80
Printing 81
Printing 82
Printing 83
Printing 84
Printing 85
Printing 86
Printing 87
Printing 88
Printing 89
Printing 90
Printing 91
Printing 92
Printing 93
Printing 94
Printing 95
Printing 96
Printing 97
Printing 98
Printing 99

任何想法 ?

發生了一些事情。 首先, Executors.newSingleThreadExecutor()使用的線程是非守護程序線程。 正如Thread的文檔所述,非守護程序線程將使JVM保持活動狀態。

Java虛擬機啟動時,通常只有一個非守護線程(通常調用某些指定類的名為main的方法)。 Java虛擬機將繼續執行線程,直到發生以下任何一種情況:

  • 已調用類Runtimeexit方法,並且安全管理器已允許進行退出操作。
  • 不是守護程序線程的所有線程都已死,要么通過從調用返回到run方法,要么拋出傳播到run方法之外的異常。

其次, ExecutorService.shutdown()不會取消任何排隊的或當前正在執行的任務。 這只是向ExecutorService發出的信號,它不再接受新任務並在所有現有任務完成后終止。 Javadoc

啟動有序關閉,在該關閉中執行先前提交的任務,但不接受任何新任務。 如果已關閉,則調用不會產生任何其他影響。

此方法不等待先前提交的任務完成執行。 使用awaitTermination可以做到這一點。

如果要立即嘗試終止ExecutorService ,則必須使用ExecutorService.shutdownNow()

嘗試停止所有正在執行的任務,暫停正在等待的任務的處理,並返回正在等待執行的任務的列表。

此方法不等待主動執行的任務終止。 使用awaitTermination可以做到這一點。

除了盡最大努力嘗試停止處理正在執行的任務之外,沒有任何保證。 例如,典型的實現將通過Thread.interrupt()取消,因此任何無法響應中斷的任務都可能永遠不會終止。

如Javadoc所述,不能保證即使使用shutdownNow也會終止執行任務。 開發人員必須對任務進行編碼以響應中斷。

這導致第三件事:您的任務無法響應中斷。 雖然當線程被InterruptedExceptionThread.sleep會拋出一個InterruptedException ,但是當拋出該異常時, 您不會脫離循環 您的代碼僅打印堆棧跟蹤,然后繼續進行下一個迭代。 為了解決這個問題,在catch塊的末尾添加一個break語句。

您還可以選擇通過Executors.newSingleThreadExecutor(ThreadFactory)使用自定義ThreadFactory 如果您擁有工廠返回守護程序線程,那么一旦主返回,JVM將退出。

shutdownNow()會嘗試中斷線程,但是您正在睡眠中捕獲中斷異常。 因此,您應該將整個代碼放在try catch塊中。

這可能對您有幫助

public class Test {

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executorService = null;
        try {
            executorService = Executors.newSingleThreadExecutor();
            Future<?> future = executorService.submit(() ->
            {
                try {
                    for (int i = 0; i < 100; i++) {
                        Thread.sleep(100);
                        System.out.println("Printing " + i);
                    }
                } catch (Exception e) {
                    System.out.println("Interrupted");
                }
            });
            future.get(5, TimeUnit.SECONDS);
            System.out.println("Reached successfully");
        } finally {
            if (executorService != null) {
                executorService.shutdownNow();
            }
        }
    }

}

TimeoutException發生在運行main()函數的線程中,而不是執行程序服務正在執行的線程中。

因此,盡管運行main函數的線程已完成執行,但JVM仍將等待所有其他正在執行的線程(在本例中為打印數字的線程)終止。

暫無
暫無

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

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