1

Channels.newChannel(is) を使用して InputStream からチャネルを作成すると、Java 標準ライブラリは次のような ReadableByteChannelImpl を返します。

   private static class ReadableByteChannelImpl
       extends AbstractInterruptibleChannel    // Not really interruptible
       implements ReadableByteChannel
   {
       InputStream in;
       private static final int TRANSFER_SIZE = 8192;
       private byte buf[] = new byte[0];
       private boolean open = true;
       private Object readLock = new Object();

       ReadableByteChannelImpl(InputStream in) {
           this.in = in;
       }

       public int read(ByteBuffer dst) throws IOException {
           int len = dst.remaining();
           int totalRead = 0;
           int bytesRead = 0;
           synchronized (readLock) {
               while (totalRead < len) {
                   int bytesToRead = Math.min((len - totalRead),
                                              TRANSFER_SIZE);
                   if (buf.length < bytesToRead)
                       buf = new byte[bytesToRead];
                   if ((totalRead > 0) && !(in.available() > 0))
                       break; // block at most once
                   try {
                       begin();
                       bytesRead = in.read(buf, 0, bytesToRead);
                   } finally {
                       end(bytesRead > 0);
                   }
                   if (bytesRead < 0)
                       break;
                   else
                       totalRead += bytesRead;
                   dst.put(buf, 0, bytesRead);
               }
               if ((bytesRead < 0) && (totalRead == 0))
                   return -1;

               return totalRead;
           }
       }

       protected void implCloseChannel() throws IOException {
           in.close();
           open = false;
       }
   }

ご覧のとおり、 read(ByteBuffer dst) を初めて呼び出すとブロックされ、再度ブロックされることはありません。見る:

           if ((totalRead > 0) && !(in.available() > 0))
               break; // block at most once

そのような奇妙な行動の背後にある理由は何ですか?

また、実際にこのチャネルを本当に中断可能にせずに AbstractInterruptibleChannel を拡張する動機は何ですか?

4

1 に答える 1

1

少なくとも1バイトがすでに読み取られていて、基なるストリームが使用可能なバイトがないことをアナウンスしている場合は、ブロックされませInputStream#available()一部のバイトが使用可能な場合でもゼロを返すことができますが、ブロックせずに読み取ることができるよりも多くのバイトを約束するべきではないことに注意してください。したがって、これは少なくとも1バイトを読み取るように努力します(提供されたバイトに少なくとも1バイトのスペースがあると仮定します)。そうすると、ストリームがさらに多くのバイトを処理することを約束しない限り、基になるストリームを再度読み取ろうとはしません。ブロッキングなしで利用できます。ReadableByteChannelByteBuffer

なぜReadableByteChannelImplextendsなのかというと、呼び出し時AbstractInterruptibleChannelにラップInputStreamが適切に閉じられるようにするためだと思います。Channel#close()そのコントラクトは。によってさらに洗練されていInterruptibleChannel#close()ます。拡張すると、スレッドセーフな開閉状態のガードを借りるAbstractInterruptibleChannelことができます。ReadableByteChannelImpl

あなたが言うように、それは少し誤った宣伝ですが、真に中断可能ではありませんが、別のスレッドから閉じられることは許容され、そうすることはべき等になります。

于 2009-12-12T22:02:30.673 に答える