[英]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.