【发布时间】:2011-05-24 10:41:33
【问题描述】:
在 Java 的上下文中,我创建一个新线程来在打开 GUI 窗口时读取网络输入,当我关闭窗口时,我想释放套接字资源并立即终止线程。现在我正在使用 setSoTimeout 方法,但我不想等待超时异常。有人可以提出一些建议吗?谢谢!
【问题讨论】:
标签: java multithreading sockets
在 Java 的上下文中,我创建一个新线程来在打开 GUI 窗口时读取网络输入,当我关闭窗口时,我想释放套接字资源并立即终止线程。现在我正在使用 setSoTimeout 方法,但我不想等待超时异常。有人可以提出一些建议吗?谢谢!
【问题讨论】:
标签: java multithreading sockets
有(可能)三种方法可以做到这一点:
在套接字上调用Socket.close() 将关闭关联的InputStream 和OutputStream 对象,并导致套接字中阻塞的任何线程或(关联的)流操作被解除阻塞。根据javadoc,对套接字本身的操作将抛出SocketException。
调用Thread.interrupt() 将(在某些未指定的情况下)中断阻塞I/O 操作,导致它抛出InterruptedIOException。
注意警告。显然,“interrupt()”方法不适用于“大多数”现代 Java 平台。 (如果其他人有时间和意愿,他们可能会调查这种方法的工作环境。但是,行为是特定于平台的这一事实应该足以说明您只应该在只需要您的应用程序时使用它在特定平台上工作。此时您可以轻松“尝试”自己。)
第三种可能的方法是调用Socket.shutdownInput() 和/或Socket.shutdownOutput()。 javadocs 没有明确说明当前被阻塞的读和/或写操作会发生什么,但认为它们会解除阻塞并抛出异常并不是不合理的。但是,如果 javadoc 没有说明会发生什么,则应假定该行为是特定于平台的。
【讨论】:
ClosedByInterruptException 仅适用于 NIO InterruptibleChannel,不适用于流或 Sockets。
我知道这个问题很老,但似乎没有人解决“现代平台”上Thread.interrupt() 的“谜团”,所以我做了一些研究。
这是在 Windows7(64 位)上的 Java 8 上测试的(但其他平台也可能如此)。
调用Thread.interrupt()不会抛出InterruptedIOException
发生的情况是InputStream.read() 方法返回并设置了-1 和Thread.interrupted()-flag。
因此,以下内容可以被视为“已纠正”的 read() 抛出 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;
}
【讨论】:
in.read(...) 阻塞,并且永远不会执行线程是否被中断的检查。