如何中断被某些套接字 IO 操作阻塞的线程而不关闭它
Posted
技术标签:
【中文标题】如何中断被某些套接字 IO 操作阻塞的线程而不关闭它【英文标题】:How to interupt a thread blocked by some socket IO operation without closing it 【发布时间】:2013-10-26 11:44:51 【问题描述】:我真的很想知道如何中断被某些 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!
【问题讨论】:
我认为当您无法访问要关闭的底层流时,您甚至无法停止它。 AFAIK 只有在阻塞操作是可中断的情况下才会起作用 @MadProgrammer 是可中断的接口吗?还是低级实现?! @parsaporahmad 不,这是一个概念。需要发生的是,阻塞线程的任何操作都需要监视该线程的中断状态,以使其可中断 在套接字上调用 Socket.close() 将关闭关联的 InputStream 和 OutputStream 对象,并且对套接字本身的操作将抛出 SocketException。 【参考方案1】:在获取SocketTimeoutException
时,在套接字上设置一个较短的读取超时并循环,每次都检查Thread.isInterrupted()
。使用Thread.interrupt()
中断线程。
【讨论】:
【参考方案2】:I/O 之类的等待任何监视器的操作是不可中断的,这就是这些情况不需要 InterruptedException
rutine 的原因,但根据 Java 7 Documentation
属于 @ 的 I/O 类987654326@ 包可以响应任何被中断的尝试,抛出流中断异常之一,其中之一是ClosedByInterruptionException
及其父类AsynchronousCloseException
。
但如果您想关闭执行头,而不是关闭流,您可以考虑使用提供取消方式的FutureTask
。
【讨论】:
【参考方案3】:看看this blog post,尤其是解决方案 4 – 带缓冲的 NIO。
简而言之:对于常规文件,您必须使用NIO
,使用扩展AbstractInterruptableChannel
的Channel
,例如。 FileChannel
.
当使用 sockets 时,使用Socket#close()
来中断/关闭。
根据 javadocs:
当前在此套接字上的 I/O 操作中阻塞的任何线程都将 抛出一个 SocketException。
但是:
解决这个问题还有另一种方法:使用NIO
的异步IO,看看here。
异步 IO 的问题在于,处理起来非常复杂(与阻塞 IO 相比),因为您将不再中继流,而是使用缓冲区。
【讨论】:
谢谢,但我仍然需要关闭流,而我不想这样做。我不想关闭流,但我想取消当前的读取操作。 没有办法做到这一点(使用阻塞操作)。如果你真的需要,我建议你异步使用NIO
。
好吧,我在这里看不出 NIO 和 IO 之间有什么大的区别,因为两者都会导致关闭套接字,除了在 IO 线程中关闭套接字,而在 NIO 中,类这样做.
使用异步 IO 时,您不必关闭套接字。你可以随时跳出select()
的循环。【参考方案4】:
如果您绝对不能/不想使用普通的 java Socket
类关闭套接字,您可以使用 java.nio.SocketChannel 来处理套接字。
SocketChannel
实现了InterruptibleChannel,可以通过中断在套接字上等待 I/O 的线程来关闭它。在这种情况下,被阻塞的读取会抛出一个ClosedByInterruptException
【讨论】:
谢谢,帮了大忙,不过就像关闭套接字一样。【参考方案5】:您可以添加这样的方法,因为任何阻塞 IO 操作都会抛出 IOException:-
public void close() throws IOException
this.socket.close();
来自 javadoc:-
关闭此套接字。当前在 accept() 中阻塞的任何线程都将 抛出一个 SocketException。
【讨论】:
不!我不想关闭流,我想取消当前的读取操作并保持流打开。 但是,如果读取可能处于消耗字节的中间@parsaporahmad,如何保持套接字打开? 我不是说关闭套接字,我想让套接字保持活动状态但暂时放弃阅读。 @parsaporahmad - 听起来您想在套接字上设置读取超时。 @jtahlborn 类似的东西【参考方案6】:注意没有InterruptedException
声明被抛出:
阅读
public int read(byte[] b) throws IOException
从输入流中读取一些字节并将它们存储到缓冲区数组 b 中。实际读取的字节数以整数形式返回。在输入数据可用、检测到文件结尾或引发异常之前,此方法会一直阻塞。
一些读取方法会通过Thread#interrupt()
响应外部中断,要么关闭流,要么抛出异常。
您不能否则停止该线程,除非以某种方式关闭或从另一个线程提供流,或者使用Thread#stop()
终止线程。最后一种方法只是最后的手段,不应出于各种原因使用。
【讨论】:
所以通过另一个线程提供流会很好,我不知道是否可能? 有可中断的 NIO 通道。【参考方案7】:不幸的是,大多数平台上的 sun java impl 不通过线程中断处理 io 中断(我相信你可以通过一些 nio 的东西来解决这个问题,不确定)。但是,我相信如果线程被阻塞从套接字读取,并且您有该套接字的句柄,您可以从另一个线程异步关闭套接字(这将中断被阻塞的线程)。
【讨论】:
你能举一些关于 nio 的例子/链接吗?我正在尝试从网络/文件中读取数据,我会中断读取线程。 @parsaporahmad - 大多数 nio 通道实现都扩展了 docs.oracle.com/javase/6/docs/api/java/nio/channels/spi/… 。以上是关于如何中断被某些套接字 IO 操作阻塞的线程而不关闭它的主要内容,如果未能解决你的问题,请参考以下文章
java 多次new DataOutputStream而不关闭,线程阻塞
如何使用 executor.execute 和 future.get() 结束任务(使线程超时)(通过上升中断)而不阻塞主线程