如何优雅地停止 运行 阻塞操作的线程?
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()
方法中被阻塞,所以这是不可能的。
解决这个问题的常用方法是什么?
对于这种情况,可以使用ServerSocket的close方法中断accept方法。这将在接受调用时阻塞的线程上抛出 SocketException。 (为了能够使用这个,你应该让你的服务器套接字对象在你想取消的地方可访问。)
一般来说,大多数阻塞 api 都有一个可以为阻塞调用指定的超时参数。或者它们可以被执行线程调用的 Thread.interrupt 方法中断。
您需要在调用 accept()
之前在服务器套接字上设置超时 [1]:
serverSocket.setSoTimeout(100);
然后,如果它在设置的超时时间内未能接受任何连接,accept()
将抛出 SocketTimeoutException
,您可以使用它来决定是否要 continue/stop 通过中断接受连接从循环或再次调用 accept()
[1] https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)
How to gracefully stop a thread that is running a blocking operation?
一般来说,你不能。但是对于某些 特定的 操作,您可以做一些事情。例如,您可以尝试中断线程。在您的例子中,您无法直接访问任务为 运行 的 Thread
,您可以使用 Future.cancel()
:
serverFuture.cancel(true);
但是阻塞操作不一定会在线程中断时被中断。那些做的通常被记录为抛出 InterruptedException
,并且不在例外 ServerSocket.accept()
中被声明为抛出。特别是对于该方法,您最好的选择可能涉及使用 ServerSocket.setSoTimeout()
为 accept()
将阻止的时间量设置一个合适的上限。使用相对较短的超时并在循环中执行 accept()
将允许您定期检查是否要中止任务。
总的来说,您需要选择一个适合您要取消的工作的策略,并且您可能需要花费一些设计精力来使该任务完全可以中断。
我在需要停止的线程中有一个阻塞操作运行:
Future serverFuture = Executors.newCachedThreadPool().submit(() -> {
var serverSocket = new ServerSocket(Config.SERVER_PORT);
serverSocket.accept(); // <-- blocking
});
serverFuture.cancel(true);
通常,我会实现一个循环,不断检查线程是否被中断并最终停止它。但是,由于线程在serverSocket.accept()
方法中被阻塞,所以这是不可能的。
解决这个问题的常用方法是什么?
对于这种情况,可以使用ServerSocket的close方法中断accept方法。这将在接受调用时阻塞的线程上抛出 SocketException。 (为了能够使用这个,你应该让你的服务器套接字对象在你想取消的地方可访问。)
一般来说,大多数阻塞 api 都有一个可以为阻塞调用指定的超时参数。或者它们可以被执行线程调用的 Thread.interrupt 方法中断。
您需要在调用 accept()
之前在服务器套接字上设置超时 [1]:
serverSocket.setSoTimeout(100);
然后,如果它在设置的超时时间内未能接受任何连接,accept()
将抛出 SocketTimeoutException
,您可以使用它来决定是否要 continue/stop 通过中断接受连接从循环或再次调用 accept()
[1] https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)
How to gracefully stop a thread that is running a blocking operation?
一般来说,你不能。但是对于某些 特定的 操作,您可以做一些事情。例如,您可以尝试中断线程。在您的例子中,您无法直接访问任务为 运行 的 Thread
,您可以使用 Future.cancel()
:
serverFuture.cancel(true);
但是阻塞操作不一定会在线程中断时被中断。那些做的通常被记录为抛出 InterruptedException
,并且不在例外 ServerSocket.accept()
中被声明为抛出。特别是对于该方法,您最好的选择可能涉及使用 ServerSocket.setSoTimeout()
为 accept()
将阻止的时间量设置一个合适的上限。使用相对较短的超时并在循环中执行 accept()
将允许您定期检查是否要中止任务。
总的来说,您需要选择一个适合您要取消的工作的策略,并且您可能需要花费一些设计精力来使该任务完全可以中断。