code: private void removeWaiter(WaitNode node) {
          if (node != null) {
              node.thread = null;
              retry:
              for (;;) {          // restart on removeWaiter race
                  for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                      s = q.next;
                      if (q.thread != null)
                          pred = q;
                      else if (pred != null) {
                          pred.next = s;
                          if (pred.thread == null) // check for race
                              continue retry;
                      }
                      else if (!U.compareAndSwapObject(this, WAITERS, q, s))
                          continue retry;
                  }
                  break;
              }
          }
      }
docs: Tries to unlink a timed-out or interrupted wait node to avoid
  accumulating garbage.  Internal nodes are simply unspliced
  without CAS since it is harmless if they are traversed anyway
  by releasers.  To avoid effects of unsplicing from already
  removed nodes, the list is retraversed in case of an apparent
  race.  This is slow when there are a lot of nodes, but we don't
  expect lists to be long enough to outweigh higher-overhead
  schemes.