docs: public void close() {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(this, tc, "close");
          }
  
          // Doing a channel.close() will actually put the keys associated with this
          // channel
          // into the associated selectors cancelledKey list, but they don't get
          // removed until the
          // next time the selector runs. In some cases, we need to make sure they are
          // really gone before we
          // we close the channel, because another thread may have requested another
          // operation
          // on the channel at the same time, which causes problems on some OS'es.
          // So, cancel them manually and wait for the selector to run once before
          // continuing
  
          // call super.close() to see if we are using Regular Sockets, and if so, let
          // the parent class handle closing the socket
          super.close();
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
              Tr.event(this, tc, "SocketChannel closing, local: " + socket.getLocalSocketAddress() + " remote: " + socket.getRemoteSocketAddress());
          }
  
          // synchronize on this SocketIOChannel to prevent duplicate closes from
          // being processed
          synchronized (this) {
              if (closed) {
                  processClose = false;
              }
              closed = true;
          }
  
          if (processClose) {
  
              // checkCancel is only on if we need to manually cancel keys as
              // the socket close() is supposed to do that for us
              if (checkCancel) {
                  // Remove socket from current selectors.
                  if (channelSelectorRead != null) {
                      SelectionKey k = channelSelectorRead.getKey(channel);
                      if (k != null) {
                          CancelRequest cr = new CancelRequest(k);
                          synchronized (cr) {
                              channelSelectorRead.addCancelRequest(cr);
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(this, tc, "waiting for read key to be canceled, key is " + k);
                              }
                              try {
                                  cr.wait();
                              } catch (InterruptedException e) {
                                  // No FFDC code needed
                              }
                          } // end-sync
                      }
                  }
                  if (channelSelectorWrite != null) {
                      SelectionKey k = channelSelectorWrite.getKey(channel);
                      if (k != null) {
                          CancelRequest cr = new CancelRequest(k);
                          synchronized (cr) {
                              channelSelectorWrite.addCancelRequest(cr);
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(this, tc, "waiting for write key to be canceled, key is " + k);
                              }
                              try {
                                  cr.wait();
                              } catch (InterruptedException e) {
                                  // No FFDC code needed
                              }
                          } // end-sync
                      }
                  }
              }
  
              try {
                  if (channel != null) {
                      channel.close();
                  }
  
                  // need to make sure the keys get cancelled after the close call
                  if (channelSelectorRead != null) {
                      channelSelectorRead.wakeup();
                      channelSelectorRead = null;
                  }
                  if (channelSelectorWrite != null) {
                      channelSelectorWrite.wakeup();
                      channelSelectorWrite = null;
                  }
  
              } catch (Throwable t) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(this, tc, "Error closing channel: " + t);
                  }
                  // ignore all shutdown/close errors
              }
          }
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(this, tc, "close");
          }
      }