private long read0(ByteBuffer[] bufs) throws IOException {
    if (bufs == null) throw new NullPointerException();
    synchronized (readLock) {
      if (!ensureReadOpen()) return -1;
      long n = 0;
      try {
        begin();
        synchronized (stateLock) {
          if (!isOpen()) return 0;
          readerThread = NativeThread.current();
        }

        for (; ; ) {
          n = Net.read(fd, bufs);
          if ((n == IOStatus.INTERRUPTED) && isOpen()) continue;
          return IOStatus.normalize(n);
        }
      } finally {
        readerCleanup();
        end(n > 0 || (n == IOStatus.UNAVAILABLE));
        synchronized (stateLock) {
          if ((n <= 0) && (!isInputOpen)) return IOStatus.EOF;
        }
        assert IOStatus.check(n);
      }
    }
  }
  public int read(ByteBuffer buf) throws IOException {

    if (buf == null) throw new NullPointerException();

    synchronized (readLock) {
      if (!ensureReadOpen()) return -1;
      int n = 0;
      try {

        // Set up the interruption machinery; see
        // AbstractInterruptibleChannel for details
        //
        begin();

        synchronized (stateLock) {
          if (!isOpen()) {
            // Either the current thread is already interrupted, so
            // begin() closed the channel, or another thread closed the
            // channel since we checked it a few bytecodes ago.  In
            // either case the value returned here is irrelevant since
            // the invocation of end() in the finally block will throw
            // an appropriate exception.
            //
            return 0;
          }

          // Save this thread so that it can be signalled on those
          // platforms that require it
          //
          readerThread = NativeThread.current();
        }

        // Between the previous test of isOpen() and the return of the
        // IOUtil.read invocation below, this channel might be closed
        // or this thread might be interrupted.  We rely upon the
        // implicit synchronization point in the kernel read() call to
        // make sure that the right thing happens.  In either case the
        // implCloseSelectableChannel method is ultimately invoked in
        // some other thread, so there are three possibilities:
        //
        //   - implCloseSelectableChannel() invokes nd.preClose()
        //     before this thread invokes read(), in which case the
        //     read returns immediately with either EOF or an error,
        //     the latter of which will cause an IOException to be
        //     thrown.
        //
        //   - implCloseSelectableChannel() invokes nd.preClose() after
        //     this thread is blocked in read().  On some operating
        //     systems (e.g., Solaris and Windows) this causes the read
        //     to return immediately with either EOF or an error
        //     indication.
        //
        //   - implCloseSelectableChannel() invokes nd.preClose() after
        //     this thread is blocked in read() but the operating
        //     system (e.g., Linux) doesn't support preemptive close,
        //     so implCloseSelectableChannel() proceeds to signal this
        //     thread, thereby causing the read to return immediately
        //     with IOStatus.INTERRUPTED.
        //
        // In all three cases the invocation of end() in the finally
        // clause will notice that the channel has been closed and
        // throw an appropriate exception (AsynchronousCloseException
        // or ClosedByInterruptException) if necessary.
        //
        // *There is A fourth possibility. implCloseSelectableChannel()
        // invokes nd.preClose(), signals reader/writer thred and quickly
        // moves on to nd.close() in kill(), which does a real close.
        // Then a third thread accepts a new connection, opens file or
        // whatever that causes the released "fd" to be recycled. All
        // above happens just between our last isOpen() check and the
        // next kernel read reached, with the recycled "fd". The solution
        // is to postpone the real kill() if there is a reader or/and
        // writer thread(s) over there "waiting", leave the cleanup/kill
        // to the reader or writer thread. (the preClose() still happens
        // so the connection gets cut off as usual).
        //
        // For socket channels there is the additional wrinkle that
        // asynchronous shutdown works much like asynchronous close,
        // except that the channel is shutdown rather than completely
        // closed.  This is analogous to the first two cases above,
        // except that the shutdown operation plays the role of
        // nd.preClose().
        for (; ; ) {
          n = Net.read(fd, buf);
          if ((n == IOStatus.INTERRUPTED) && isOpen()) {
            // The system call was interrupted but the channel
            // is still open, so retry
            continue;
          }
          return IOStatus.normalize(n);
        }

      } finally {
        readerCleanup(); // Clear reader thread
        // The end method, which is defined in our superclass
        // AbstractInterruptibleChannel, resets the interruption
        // machinery.  If its argument is true then it returns
        // normally; otherwise it checks the interrupt and open state
        // of this channel and throws an appropriate exception if
        // necessary.
        //
        // So, if we actually managed to do any I/O in the above try
        // block then we pass true to the end method.  We also pass
        // true if the channel was in non-blocking mode when the I/O
        // operation was initiated but no data could be transferred;
        // this prevents spurious exceptions from being thrown in the
        // rare event that a channel is closed or a thread is
        // interrupted at the exact moment that a non-blocking I/O
        // request is made.
        //
        end(n > 0 || (n == IOStatus.UNAVAILABLE));

        // Extra case for socket channels: Asynchronous shutdown
        //
        synchronized (stateLock) {
          if ((n <= 0) && (!isInputOpen)) return IOStatus.EOF;
        }

        assert IOStatus.check(n);
      }
    }
  }