Как изящно остановить поток, который выполняет операцию блокировки? - PullRequest
0 голосов
/ 27 января 2019

У меня есть операция блокировки, выполняемая в потоке, которую мне нужно остановить:

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

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

serverFuture.cancel(true);

Обычно, я бы реализовал цикл, который бы продолжал проверять, прерывается ли поток, и в конце концов останавливал его.Однако поскольку поток заблокирован в методе serverSocket.accept(), это невозможно.

Как обычно можно решить эту проблему?

Ответы [ 3 ]

0 голосов
/ 27 января 2019

Вам необходимо установить тайм-аут на сокете сервера перед вызовом accept() [1]:

serverSocket.setSoTimeout(100);

Тогда, если ему не удалось принять какое-либо соединение в течение установленного тайм-аута, accept() выдаст SocketTimeoutException который вы можете использовать, чтобы решить, хотите ли вы продолжить / прекратить принимать соединения, либо прерывая цикл, либо снова вызывая accept()

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

0 голосов
/ 27 января 2019

Как изящно остановить поток, выполняющий операцию блокировки?

В общем, вы не можете.Но есть вещи, которые вы можете сделать с некоторыми конкретными операциями.Например, вы можете попытаться прервать поток.В случае, таком как ваш пример, когда у вас нет прямого доступа к Thread, в котором выполняется задача, вы можете использовать Future.cancel():

serverFuture.cancel(true);

Но операции блокировки не обязательнобыть прерванным, когда их темы делают.Те, кто это делает, как правило, задокументированы для выброса InterruptedException, и это не входит в число исключений ServerSocket.accept() объявлено для выброса.В частности, для этого метода ваша лучшая ставка, вероятно, предполагает использование ServerSocket.setSoTimeout() для установки подходящей верхней границы на количество времени, которое accept() заблокирует.Использование относительно короткого времени ожидания и выполнение accept() в цикле позволит вам периодически проверять, прерывать ли задачу.

В целом, вам необходимо выбрать стратегию, соответствующую той работе, которую вы пытаетесь выполнить.отмените, и вам, возможно, придется потратить некоторые усилия на проектирование, чтобы сделать эту задачу полностью прерываемой.

0 голосов
/ 27 января 2019

В этом случае Вы можете использовать close метод ServerSocket для прерывания метода приема.Это вызовет исключение SocketException в потоке, заблокированном при вызове accept.(Чтобы это можно было использовать, вы должны сделать доступным объект сокета вашего сервера там, где вы хотите отменить.)

В большинстве случаев блокирование API имеет параметр тайм-аута, который можно указать для вызова блокировки.Или же они могут быть прерваны с помощью метода Thread.interrupt, вызываемого для исполняющего потока.

...