// AbstractInterruptibleChannel synchronizes invocations of this method
  // using AbstractInterruptibleChannel.closeLock, and also ensures that this
  // method is only ever invoked once.  Before we get to this method, isOpen
  // (which is volatile) will have been set to false.
  //
  protected void implCloseSelectableChannel() throws IOException {
    synchronized (stateLock) {
      isInputOpen = false;
      isOutputOpen = false;

      closeImpl();

      // Signal native threads, if needed.  If a target thread is not
      // currently blocked in an I/O operation then no harm is done since
      // the signal handler doesn't actually do anything.
      //
      if (readerThread != 0) NativeThread.signal(readerThread);

      if (writerThread != 0) NativeThread.signal(writerThread);

      // If this channel is not registered then it's safe to close the fd
      // immediately since we know at this point that no thread is
      // blocked in an I/O operation upon the channel and, since the
      // channel is marked closed, no thread will start another such
      // operation.  If this channel is registered then we don't close
      // the fd since it might be in use by a selector.  In that case
      // closing this channel caused its keys to be cancelled, so the
      // last selector to deregister a key for this channel will invoke
      // kill() to close the fd.
      //
      if (!isRegistered()) kill();
    }
  }
  protected void implCloseSelectableChannel() throws IOException {
    synchronized (stateLock) {
      if (state != ST_KILLED) nd.preClose(fd);
      ResourceManager.afterUdpClose();

      // if member of mulitcast group then invalidate all keys
      if (registry != null) registry.invalidateAll();

      long th;
      if ((th = readerThread) != 0) NativeThread.signal(th);
      if ((th = writerThread) != 0) NativeThread.signal(th);
      if (!isRegistered()) kill();
    }
  }
 public void shutdownOutput() throws IOException {
   synchronized (stateLock) {
     if (!isOpen()) throw new ClosedChannelException();
     isOutputOpen = false;
     shutdown(fd, SHUT_WR);
     if (writerThread != 0) NativeThread.signal(writerThread);
   }
 }