Reputation: 5779
I have a blocking operation running in a thread that I need to stop:
Future serverFuture = Executors.newCachedThreadPool().submit(() -> {
var serverSocket = new ServerSocket(Config.SERVER_PORT);
serverSocket.accept(); // <-- blocking
});
serverFuture.cancel(true);
Normally, I'd implement a loop that would keep checking whether the thread is interrupted and stop it eventually. However, since the thread is blocked in the serverSocket.accept()
method, this is not possible.
What is the usual way to overcome this problem?
Upvotes: 1
Views: 173
Reputation: 15663
You need to set timeout on the server socket before calling accept()
[1]:
serverSocket.setSoTimeout(100);
Then if it failed to accept any connection within the set timeout, accept()
will throw SocketTimeoutException
which you can use to decide if you want to continue/stop accepting connections by either breaking from the loop or calling accept()
again
[1] https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)
Upvotes: 0
Reputation: 180058
How to gracefully stop a thread that is running a blocking operation?
In general, you can't. But there are things you can do about some specific operations. For example, you can try interrupting the thread. In a case such as your example, where you don't have direct access to the Thread
in which the task is running, you can use Future.cancel()
:
serverFuture.cancel(true);
But blocking operations do not necessarily get interrupted when their threads do. Those that do are generally documented to throw InterruptedException
, and that is not among the exceptions ServerSocket.accept()
is declared to throw. For that method in particular, your best bet probably involves using ServerSocket.setSoTimeout()
to put a suitable upper bound on the amount of time that accept()
will block. Using a relatively short timeout and performing the accept()
in a loop would allow you to check periodically whether to abort the task.
Overall, then, you need to choose a strategy appropriate to the work you are trying to cancel, and you may need to expend some design effort to make that task cleanly interruptible.
Upvotes: 2
Reputation: 7938
For this case, You can use close method of ServerSocket to interrupt accept method. This will throw SocketException on the thread that is blocked on the accept call. (To be able to use this, you should make your server socket object accessible where you want to cancel.)
In general most of blocking api's has a timeout parameter that can be specified for the blocking call. Or they can be interrupted with Thread.interrupt method called for the executing thread.
Upvotes: 0