【问题标题】:How to interupt a thread blocked by some socket IO operation without closing it如何中断被某些套接字 IO 操作阻塞的线程而不关闭它
【发布时间】: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。

标签: java multithreading sockets io stream


【解决方案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,使用扩展AbstractInterruptableChannelChannel,例如。 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 的东西来解决这个问题,不确定)。但是,我相信如果线程被阻塞从套接字读取,并且您有该套接字的句柄,您可以从另一个线程异步关闭套接字(这将中断被阻塞的线程)。

      【讨论】:

      猜你喜欢
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-01
      • 2013-10-05
      • 2014-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多