docs: public void run () {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "run");
  
      //A thread is now processing the queue.
      running = true;
  
      /*
       *Can't use the running flag here as can allow multiple threads to be running at the same time. For example:
       *
       *Thread 1 is performing run processing, there is nothing left on the queue so it sets running to false.
       *Another thread calls enqueue, running is false so another thread, thread 2 is started.
       *Thread 2 enters the run method and sets running to true.
       *Thread 1 loops round, reads the running flag which is now true so carries on processing. We now get two threads in the run method.
       */
      boolean continueProcessing = true;
  
      while (continueProcessing) { // Thread should still run
        try {
          //Get invocation but don't dequeue it.
          //Only perform dequeue once invocation has been invoked otherwise a race condition can arise with threads
          //that are dispatching to all non-empty dispatch queues. See defect 538065 for more details.
          final AbstractInvocation invocation = head();
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "invocation=" + invocation);
  
          final Dispatchable dispatchable = invocation.getDispatchable();
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "dispatchable="+ dispatchable);
  
          //Whether the invocation should be repooled after it has been invoked.
          boolean repoolInvocation = false;
  
          //Need to be got when holding lock on invocation.
          final int size;
          final Conversation.ConversationType conversationType;
  
          // Synchronize on the item as it may have been dispatched to all queues, in
          // which case we do not want to risk corrupting its reference count.
          synchronized (invocation) {
            invocation.decrementReferenceCount();
  
            // If this this the last thread to 'see' the invocation - and it is ready (ie. the thread that
            // queued it is no longer considering invoking it) then invoke the method represented by the
            // invocation object.
            if (invocation.getReferenceCount() == 0 && invocation.isReady()) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Invoking: "+ invocation);
  
              invocation.invoke();
  
              final ConversationImpl convImpl = (ConversationImpl)invocation.getConversation();
              synchronized (convImpl.getTotalOutstandingRequestCountLock()) {
                convImpl.decrementTotalOutstandingCount();
  
                // Check to see if we have processed all outstanding invocation requests
                // for the conversation.  If so, deliver any errors to the SIConnections
                // event listener.  This prevents error delivery preceeding responses to
                // API calls that might have generated the error.
                if (convImpl.getTotalOutstandingRequestCount() == 0) {
                  final AbstractInvocation errorInvoc = convImpl.getErrorOccurredInvocation();
                  if (errorInvoc != null) {
                    errorInvoc.invoke();
                    errorInvoc.repool();
                    convImpl.setErrorOccurredInvocation(null);
                  }
                }
              }
  
              //Now that invocation has been invoked, repool it.
              repoolInvocation = true;
            } else {
              //AbstractInvocation.toString includes refCount and ready flag information so no need for extra information.
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Not invoking " + invocation + " at this time");
            }
  
  
            //Need to do this when holding the invocation lock in order to ensure values don't get reset by another
            //thread repooling invocation at the same.
            size = invocation.getSize();
  
            final Connection connection = invocation.getConnection();
            if (connection != null) {
              conversationType = connection.getConversationType();
            } else {
              conversationType = null;
            }
          }
  
          //We are now done with invocation, dequeue it regardless of whether we invoked it or not.
          dequeue();
  
          //Unlock barrier using stashed information.
          unlockBarrier(size, conversationType);
  
          //All done, repool invocation.
          if(repoolInvocation) invocation.repool();
  
          // Reduce the conversation's use count for this dispatch queue.
          // If this hits zero then disassociate the conversation from this queue.
  
          synchronized (dispatchable.getDispatchLockObject()) {
            dispatchable.decrementDispatchQueueRefCount();
            if (dispatchable.getDispatchQueueRefCount() == 0) {
              dispatchable.setDispatchQueue(null);
            }
          }
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Dispatchable refCount = " + dispatchable.getDispatchQueueRefCount());
  
          // The queue may now be empty but to ensure correct synchronisation with enqueue synchronise on this object
  
          synchronized (this) {
            if (isEmpty()) {
              if (emptyDispatchQueues != null) {
                synchronized (emptyDispatchQueues) {
                  emptyDispatchQueues.add(this);
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Added this queue (" + this + ") to empty dispatch list ("+emptyDispatchQueues+")");
                }
              }
  
              // Sleep for a few seconds to see if more work comes in. This is done to avoid the contention on the WAS
              // threadpool that backs the dispatch queues.
  
              try {
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Thread waiting " + rldThreadRepoolDelay + "ms for new work to arrive");
                wait(rldThreadRepoolDelay);
              } catch (InterruptedException e) {
                // No FFDC Code Needed
              }
  
              //Do we need to continue processing?
              continueProcessing = !isEmpty();
  
              // If we are to continue processing remove ourselves from the emptyDispatchQueues list
              if (continueProcessing) {
                if (emptyDispatchQueues != null) {
                  synchronized (emptyDispatchQueues) {
                    emptyDispatchQueues.remove(this);
                    if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Removed this queue (" + this + ") from empty dispatch list ("+emptyDispatchQueues+")");
                  }
                }
              }
  
              //Indicate whether a new thread needs to be started to process future work.
              running = continueProcessing;
            }
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "continue running thread="+continueProcessing);
          }
        } catch(Throwable e) {
          FFDCFilter.processException(e, "com.ibm.ws.sib.jfapchannel.impl.rldispatcher.ReceiveListenerDispatchQueue.run", JFapChannelConstants.RLDISPATCHQUEUE_RUN_01, this);
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "ReceiveListenerDispatchQueue thread caught exception: ", e);
          if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, e);
        }
      } // while (continueProcessing)
  
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "run");
    }