簡體   English   中英

如何正常停止正在運行阻塞操作的線程?

[英]How to gracefully stop a thread that is running a blocking operation?

我有一個阻塞操作在我需要停止的線程中運行:

Future serverFuture = Executors.newCachedThreadPool().submit(() -> {
    var serverSocket = new ServerSocket(Config.SERVER_PORT);

    serverSocket.accept(); // <-- blocking
});

serverFuture.cancel(true);

通常,我會實現一個循環來繼續檢查線程是否被中斷並最終停止它。 但是,由於線程在serverSocket.accept()方法中被阻塞,因此這是不可能的。

解決這個問題的常用方法是什么?

如何正常停止正在運行阻塞操作的線程?

一般來說,你不能。 但是你可以對某些特定的操作做些事情。 例如,您可以嘗試中斷線程。 在您的示例中,您無法直接訪問運行任務的Thread ,您可以使用Future.cancel()

serverFuture.cancel(true);

但是阻塞操作不一定會在線程執行時中斷。 那些做的事情通常被記錄為拋出InterruptedException ,並且這不是ServerSocket.accept()被聲明拋出的異常。 特別是對於該方法,最好的選擇可能是使用ServerSocket.setSoTimeout()accept()阻塞的時間量上設置合適的上限。 使用相對較短的超時並在循環中執行accept()將允許您定期檢查是否中止任務。

總的來說,您需要選擇適合您要取消的工作的策略,並且您可能需要花費一些設計工作來使該任務完全可以中斷。

對於這種情況,您可以使用ServerSocket的close方法來中斷accept方法。 這將在接受調用上阻塞的線程上拋出SocketException。 (為了能夠使用它,您應該使您的服務器套接字對象可以在您想要取消的位置訪問。)

通常,大多數阻塞api都有一個可以為阻塞調用指定的超時參數。 或者可以使用為執行線程調用的Thread.interrupt方法中斷它們。

在調用accept() [1]之前,需要在服務器套接字上設置超時:

serverSocket.setSoTimeout(100);

然后,如果它在設置超時內未能接受任何連接,則accept()將拋出SocketTimeoutException ,您可以使用它來決定是否要通過斷開循環或再次調用accept()來繼續/停止接受連接

[1] https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)

暫無
暫無

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

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