我真的很想知道如何中断被某些I/O操作阻塞的线程?I/O 是通过套接字进行的,我不想close()
套接字。
我尝试使用Thread.interrupt()
中断线程,但没有成功。
被 IO 操作阻止的线程:
void run(){
byte[] data=new byte[1024];
in.read(data);//blocked!
}
中断阻塞线程的线程(不起作用):
void run(){
blockedThread.interrupt();//no success!
}
套接字和SocketTimeoutException
循环上设置一个短暂的读取超时,每次都检查Thread.isInterrupted()
。使用 Thread.interrupt()
中断线程。
如果你绝对不能/不想使用普通的java Socket
类关闭套接字,你可以使用java.nio.SocketChannel来处理套接字。
SocketChannel
实现了可中断通道,可以通过中断在套接字上等待 I/O 的线程来关闭该通道。在这种情况下,被阻止的读取将抛出 ClosedByInterruptException
您可以添加这样的方法,因为任何阻塞 IO 操作都会抛出 IOException:-
public void close() throws IOException {
this.socket.close();
}
来自javadoc:-
关闭此套接字。当前在accept()中被阻止的任何线程都将 抛出套接字异常。
不幸的是,大多数平台上的 sun java impl 不会通过线程中断来处理 io 中断(我相信你可以通过一些 nio 的东西来解决这个问题,不确定)。 但是,我相信如果线程被阻止从套接字读取,并且您有该套接字的句柄,则可以从另一个线程异步关闭套接字(这将中断阻塞的线程)。
请注意,没有声明要抛出InterruptedException
:
读
public int read(byte[] b) throws IOException
从输入流中读取一定数量的字节,并将它们存储到缓冲数组 b 中。实际读取的字节数以整数形式返回。此方法将一直阻止,直到输入数据可用、检测到文件结尾或引发异常。
一些读取方法将通过Thread#interrupt()
响应外部中断,要么关闭流,要么抛出异常。
否则,如果不以某种方式关闭或从另一个线程提供流,或者通过使用 Thread#stop()
终止线程,则无法停止此线程。最后一种方法只是最后的手段,不应出于各种原因使用。
看看这篇博文,尤其是解决方案 4 – 带有缓冲的 NIO。
简而言之:对于常规文件,您必须使用 NIO
,使用扩展AbstractInterruptableChannel
的Channel
,例如。 FileChannel
.
使用套接字时,请使用Socket#close()
中断/关闭。
根据javadocs:
此套接字上的 I/O 操作中当前阻塞的任何线程都将 抛出套接字异常。
但:
还有另一种解决方法:将异步IO与NIO
一起使用,看看这里。异步 IO 的问题在于,处理起来非常复杂(与阻塞 IO 相比),因为您将不再在流上中继,而是在缓冲区上中继。
等待任何监视器的操作一样的I/O是不可中断的,这就是这些情况不需要InterruptedException
芦丁的原因,但是根据Java 7 Documentation
属于nio
包的I/O类可以响应任何尝试入抛出流中断异常之一,其中之一是ClosedByInterruptionException
,并且它的父类AsynchronousCloseException
。
但是,如果您想关闭执行头,而不是关闭流,您可以考虑使用提供取消方式的FutureTask
。