【问题标题】:Why does "piping" a CharBuffer hang?为什么“管道” CharBuffer 挂起?
【发布时间】:2008-09-24 15:03:58
【问题描述】:

为什么下面的方法会挂起?

公共无效管道(读入,写出){ CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); 而(in.read(buf)>= 0){ out.append(buf.flip()); } }

【问题讨论】:

    标签: java io pipe


    【解决方案1】:

    回答我自己的问题:您必须在reads 之间致电buf.clear()。据推测,read 挂起是因为缓冲区已满。正确的代码是

    公共无效管道(读入,写出){ CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); 而(in.read(buf)> = 0){ out.append(buf.flip()); buf.clear(); } }

    【讨论】:

    • 挂了?查看 Readable API,如果缓冲区已满,我希望它在每次读取时忙循环返回 0,但这是一个猜测,因为它没有明确说明“尝试读取”的含义。挂起可能意味着因为您正在多次写入输出,所以您已经阻止了输出。
    • 我没有检查循环的详细行为。读取块或重复返回 0。最终效果:循环永远不会终止。
    • 我猜要阻塞发生,输出流必须是具有有限容量且未被耗尽的东西,例如循环缓冲区 - 非常罕见的情况。也许我的特殊之处在于我通常使用“挂起”来表示死锁而不是活锁。
    【解决方案2】:

    我认为这是一个死锁。 in.read(buf) 锁定 CharBuffer 并阻止 out.append(buf) 调用。

    假设 CharBuffer 在实现中使用了(某种)锁。 API 对 CharBuffer 类有何看法?

    编辑:抱歉,我的大脑短路了……我把它和别的东西弄混了。

    【讨论】:

      【解决方案3】:

      CharBuffers 与 Readers 和 Writers 的工作并不像您预期​​的那样干净。特别是,没有Writer.append(CharBuffer buf) 方法。问题sn-p调用的方法是Writer.append(CharSequence seq),它只是调用了seq.toString()CharBuffer.toString() 方法确实返回缓冲区的字符串值,但它不会耗尽缓冲区。随后对Reader.read(CharBuffer buf) 的调用获得了一个已满的缓冲区,因此返回 0,从而强制循环无限期地继续。

      虽然这感觉像是挂起,但实际上它是在每次通过循环时将第一次读取的缓冲区内容附加到写入器。因此,您要么开始在目标中看到大量输出,要么写入器的内部缓冲区会增长,具体取决于写入器的实现方式。

      尽管很烦人,但我建议使用 char[] 实现,前提是因为 CharBuffer 解决方案每次通过循环都会构建至少两个新的 char[]。

      public void pipe(Reader in, Writer out) throws IOException {
          char[] buf = new char[DEFAULT_BUFFER_SIZE];
          int count = in.read(buf);
          while( count >= 0 ) {
              out.write(buf, 0, count);
              count = in.read(buf);
          }
      }
      

      我建议您仅在需要支持两种字符编码之间的转换时才使用此方法,否则即使您正在传输字符,也最好使用 ByteBuffer/Channel 或 byte[]/IOStream 实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-14
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多