Как правильно остановить поток, ожидающий сетевой активности? - PullRequest
4 голосов
/ 20 августа 2011

В прошлом этот вопрос, без сомнения, задавался в различных формах, но не столько для конкретного сценария.

Какой самый правильный способ остановить поток, который блокирует, ожидая получения сетевого сообщения по UDP.

Например, скажем, у меня есть следующая тема:

public class ClientDiscoveryEngine extends Thread {

    private final int PORT;

    public ClientDiscoveryEngine(final int portNumber) {
        PORT = portNumber;
    }

    @Override
    public void run() {
        try {
            socket = new DatagramSocket(RECEIVE_PORT);

            while (true) {
                final byte[] data = new byte[256];
                final DatagramPacket packet = new DatagramPacket(data, data.length);

                socket.receive(packet);
            }
        } catch (SocketException e) {
            // do stuff 1
        } catch (IOException e) {
            // do stuff 2
        }
    }
}

Теперь, будет ли более правильный способ использовать метод interrupt()? Например, добавив следующий метод:

@Override
public void interrupt() {
    super.interrupt();
    // flip some state?
}

Меня беспокоит только то, не является ли socket.receive() непрерываемым методом блокировки? Единственный способ, о котором я подумал, - это реализовать метод прерывания, как описано выше, в этом вызове метода socket.close(), а затем обработать его в методе run в улове для SocketException. Или, возможно, вместо while(true) используйте какое-то состояние, которое переворачивается в методе прерывания. Это лучший способ? Или есть более элегантный способ?

Спасибо

Ответы [ 4 ]

4 голосов
/ 20 августа 2011

Метод приема, похоже, не прерываемый.Вы можете закрыть сокет: javadoc говорит:

Любой поток, в настоящий момент заблокированный в receive(java.net.DatagramPacket) на этом сокете, выдаст SocketException

Вы также можете использовать setSoTimeoutсделать блок метода приема только на небольшое количество времени.После возврата метода ваш поток может проверить, не был ли он прерван, и повторить попытку получения в течение этого небольшого промежутка времени.

3 голосов
/ 20 августа 2011
2 голосов
/ 20 августа 2011

Чтобы остановить поток, пользователь не должен ни прерывать, ни останавливаться в Java. Наилучший способ, как вы предложили в конце вашего вопроса, состоит в том, чтобы цикл внутри основного метода контролировался флагом, который вы можете поднимать по мере необходимости.

Вот старая ссылка об этом: http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

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

Кроме того, если вы хотите избежать блокировки вашего потока в каком-либо состоянии ввода-вывода, ожидая сокета, вы должны дать вашему сокету соединение и время ожидания чтения (метод setSoTimeout).

С уважением, Stéphane

0 голосов
/ 21 августа 2011

Это один из самых простых.Если он заблокирован на сокете UDP, отправьте сокету сообщение UDP, которое инструктирует принимающий поток «остановить».

Rgds, Martin

...