docs: @Override
      public void run() {
  
          int numItemsToWorkOn = 0;
          long lastPruneTime = 0;
          long lastCheckTime = 0;
          int listSize = 1;
          int i = 0;
          int sleepTime = AsyncProperties.timerSleepTime;
          int batchLimitSize = AsyncProperties.timerBatchSize;
          boolean sleepAlways = AsyncProperties.timerSleepAlways;
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "Timeout thread running with the following parameters");
              Tr.debug(tc, "numQueues:      " + numQueues);
              Tr.debug(tc, "sleepAlways:    " + sleepAlways);
              Tr.debug(tc, "sleepTime:      " + sleepTime);
              Tr.debug(tc, "batchLimitSize: " + batchLimitSize);
          }
  
          TimerWorkItem[] workItems = new TimerWorkItem[batchLimitSize];
  
          long currentTime = CHFWBundle.getApproxTime();
  
          while (true) {
              if ((listSize == 0) || sleepAlways) {
                  try {
                      Thread.sleep(sleepTime);
                  } catch (InterruptedException ie) {
                      // ignore and go on
                  }
              }
  
              numItemsToWorkOn = 0;
  
              if ((this.queueToUse == 1) || (numQueues == 1)) {
                  this.queueToUse = 2;
                  synchronized (this.requestQueue1) {
                      listSize = this.requestQueue1.size();
                      if (listSize != 0) {
                          i = 0;
                          while (i < listSize && numItemsToWorkOn < batchLimitSize) {
                              workItems[numItemsToWorkOn] = this.requestQueue1.removeFirst();
  
                              // only work on the entry if it hasn't been cancelled
                              if (workItems[numItemsToWorkOn].state != TimerWorkItem.ENTRY_CANCELLED) {
                                  numItemsToWorkOn++;
                              }
                              i++;
                          }
                      }
                  } // end synchronized (requestQueue1)
              } else {
                  this.queueToUse = 1;
                  synchronized (this.requestQueue2) {
                      listSize = this.requestQueue2.size();
                      if (listSize != 0) {
                          i = 0;
                          while (i < listSize && numItemsToWorkOn < batchLimitSize) {
                              workItems[numItemsToWorkOn] = this.requestQueue2.removeFirst();
  
                              // only work on the entry if it hasn't been cancelled
                              if (workItems[numItemsToWorkOn].state != TimerWorkItem.ENTRY_CANCELLED) {
                                  numItemsToWorkOn++;
                              }
                              i++;
                          }
                      }
                  } // end synchronized (requestQueue2)
              }
  
              // process what we took off the list
              for (i = 0; i < numItemsToWorkOn; i++) {
                  // check again, since looping takes time
                  if (workItems[i].state != TimerWorkItem.ENTRY_CANCELLED) {
                      insertWorkItem(workItems[i], currentTime);
                  }
              }
  
              currentTime = CHFWBundle.getApproxTime();
  
              if ((currentTime - lastCheckTime > TIMEOUT_CHECKING_THRESHOLD)) {
                  checkForTimeouts(currentTime);
                  lastCheckTime = currentTime;
              }
  
              if ((currentTime - lastPruneTime) > TIMESLOT_PRUNING_THRESHOLD) {
                  timeSlotPruning(currentTime);
                  lastPruneTime = currentTime;
              }
  
          } // end while(true)
      }