我在需要停止的线程中运行了阻塞操作:
main
通常,我会实现一个循环,该循环将不断检查线程是否被中断并最终将其停止。但是,由于线程在Future serverFuture = Executors.newCachedThreadPool().submit(() -> {
var serverSocket = new ServerSocket(Config.SERVER_PORT);
serverSocket.accept(); // <-- blocking
});
serverFuture.cancel(true);
方法中被阻塞,所以这是不可能的。
解决此问题的常用方法是什么?
答案 0 :(得分:3)
如何正常停止正在运行阻塞操作的线程?
通常,您不能。但是对于某些特定的操作,您可以做一些事情。例如,您可以尝试中断线程。在您的示例中,如果您无权直接访问运行任务的Thread
,则可以使用Future.cancel()
:
serverFuture.cancel(true);
但是阻塞操作不一定会在其线程发生时被中断。通常,有记录的文件会抛出InterruptedException
,而声明为ServerSocket.accept()
的异常除外。特别是对于该方法,最好的选择可能是使用ServerSocket.setSoTimeout()
为accept()
阻塞的时间量设置一个合适的上限。使用相对较短的超时并循环执行accept()
可以使您定期检查是否中止任务。
总的来说,您需要选择一种适合您要取消的工作的策略,并且可能需要花费一些设计工作才能使该任务完全可中断。
答案 1 :(得分:0)
在这种情况下,可以使用ServerSocket的close方法来中断accept方法。这将在被接受调用阻塞的线程上抛出SocketException。 (要使用此功能,应使服务器套接字对象在您要取消的位置可访问。)
通常,大多数阻塞api都有一个可以为阻塞调用指定的超时参数。或者可以通过执行线程调用的Thread.interrupt方法来中断它们。
答案 2 :(得分:0)
您需要在调用accept()
[1]之前在服务器套接字上设置超时时间:
serverSocket.setSoTimeout(100);
然后,如果它未能在设置的超时时间内接受任何连接,则accept()
将抛出SocketTimeoutException
,您可以通过中断循环或通过中断来决定是否要继续/停止接受连接。再次致电accept()
[1] https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)