code: final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
          Mutex lock = this.lock;
          WorkQueue w = null;
          if (wt != null && (w = wt.workQueue) != null) {
              w.runState = -1;                // ensure runState is set
              stealCount.getAndAdd(w.totalSteals + w.nsteals);
              int idx = w.poolIndex;
              lock.lock();
              try {                           // remove record from array
                  WorkQueue[] ws = workQueues;
                  if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w)
                      ws[idx] = null;
              } finally {
                  lock.unlock();
              }
          }
  
          long c;                             // adjust ctl counts
          do {} while (!U.compareAndSwapLong
                       (this, CTL, c = ctl, (((c - AC_UNIT) & AC_MASK) |
                                             ((c - TC_UNIT) & TC_MASK) |
                                             (c & ~(AC_MASK|TC_MASK)))));
  
          if (!tryTerminate(false, false) && w != null) {
              w.cancelAll();                  // cancel remaining tasks
              if (w.array != null)            // suppress signal if never ran
                  signalWork();               // wake up or create replacement
              if (ex == null)                 // help clean refs on way out
                  ForkJoinTask.helpExpungeStaleExceptions();
          }
  
          if (ex != null)                     // rethrow
              U.throwException(ex);
      }
docs: Final callback from terminating worker, as well as upon failure
  to construct or start a worker in addWorker.  Removes record of
  worker from array, and adjusts counts. If pool is shutting
  down, tries to complete termination.
  
  @param wt the worker thread or null if addWorker failed
  @param ex the exception causing failure, or null if none