Как немедленно завершить блокировку потока при операции ввода-вывода сокета?

В контексте Java я создаю новый поток для чтения сетевого ввода, когда открываю окно GUI, и когда я закрываю окно, я хочу освободить ресурс сокета и немедленно прекратить поток. Теперь я использую метод setSoTimeout, но я не хочу ждать исключения тайм-аута. Может ли кто-нибудь дать какое-нибудь предложение? Спасибо!

Ответ 1

Есть (потенциально) три способа сделать это:

  • Вызов Socket.close() в сокете закроет связанные объекты InputStream и OutputStream и вызовет блокирование любых потоков в Socket или (связанных) потоковых операциях, которые должны быть разблокированы. Согласно javadoc, операции с самим сокером будут вызывать SocketException.

  • Вызов Thread.interrupt() будет (при некоторых обстоятельствах, которые не указаны) прервать операцию блокирующего ввода-вывода, бросьте InterruptedIOException.

    Обратите внимание на оговорку. По-видимому, подход "interrupt()" не работает на "большинстве" современных платформ Java. (Если у кого-то еще было время и склонность, они могли бы расследовать обстоятельства, в которых работает этот подход. Однако сам факт, что поведение является специфичным для платформы, должен быть достаточным, чтобы сказать, что вы должны использовать его только в том случае, если вам нужна ваша заявка для работы на определенной платформе. В этот момент вы можете легко "попробовать" для себя.)

  • Возможный третий способ сделать это - вызвать Socket.shutdownInput() и/или Socket.shutdownOutput(). В javadocs явно не указано, что происходит с операциями чтения и/или записи, которые в настоящее время заблокированы, но небезосновательно думать, что они разблокируют и выдают исключение. Однако, если javadoc не говорит, что происходит, тогда поведение следует считать специфичным для платформы.

Ответ 2

Я знаю, что этот вопрос старый, но, как кажется, никто не решил "тайну" Thread.interrupt() на "современных платформах", я сделал некоторые исследования.

Это проверено на Java 8 на Windows7 (64-разрядная версия) (но это, вероятно, будет верно и для других платформ).

Вызов Thread.interrupt() делает не бросок InterruptedIOException Случается, что метод InputStream.read() возвращается с параметрами -1 и Thread.interrupted() -flag.

Таким образом, можно считать "исправленное" чтение() throw InterruptedIOException:

static final int read(Socket socket, byte[] inData) 
    throws SocketTimeoutException, // if setSoTimeout() was set and read timed out
           InterruptedIOException, // if thread interrupted
           IOException             // other erors
{
    InputStream in = socket.getInputStream();

    int readBytes = in.read( inData, 0, inData.length);

    if  ( Thread.interrupted() )
    {
        throw new InterruptedIOException( "Thread interrupted during socket read");
    }

    return readBytes;
}