@SuppressWarnings("unchecked")
        public void run() {
            if (startTimeNsec == 0) {
                startTimeNsec = System.nanoTime();
            }

            synchronized (rehashMonitor) {
                boolean boolval;

                // Fast forward to make room for at least the current count. Useful for cases
                // where inserts are happening so quickly that the capacity used to trigger
                // the resizer is stale by the time we get here...
                int needed_capacity  = Math.max(capacity, (int)(elementCount / loadFactor));

                needed_capacity = calculateCapacity((capacity == 0 ? 1 : needed_capacity << 1));

                if (resizingIntoElementData == null) {
                    resizingIntoElementData = newElementArray(needed_capacity);
                    if (!isSynchronous) {
                        cachedExpectedHeadsArray = newElementArray(needed_capacity);
                    }
                }

                int length = resizingIntoElementData.length;

                // Force a full fence:
                boolval = volatileUpdateIndicator.get();
                volatileUpdateIndicator.set(!boolval);

                if (isSynchronous) {
                    observedResizingIntoTable = true;
                }

                if (!observedResizingIntoTable) {
                    // This is effectively a spin-wait until the mutator has signaled that it has
                    // observed the new Element array.

                    if ((System.nanoTime() - startTimeNsec) > NSEC_TIME_TO_SPINWAIT_IN_RESIZER_BEFORE_GIVING_UP) {
                        // stop spinning, and instead make a future mutator op kick off another resizer.
                        needToKickOffAnotherBackgroundResize = true;
                        return;
                    }

                    // We spin wait by scheduling ourselves for a new execution so as not to block other
                    // users of the executors thread pool.
                    backgroundResizers.schedule(this, 1, TimeUnit.MILLISECONDS);

                    return;
                }

                for (int i = 0; i < elementData.length; i++) {
                    Entry<K, V> existingEntry = elementData[i];

                    while (existingEntry != null) {
                        int bucketIndex = existingEntry.origKeyHash & (length - 1);

                        insertUniqueEquivalentAtHeadOfBucket(existingEntry, bucketIndex);

                        existingEntry = existingEntry.next;
                    }
                    elementData[i] = null;
                }

                // Force a StoreStore fence:
                volatileUpdateIndicator.lazySet(!boolval);

                // We don't need the expected head cache any more:
                cachedExpectedHeadsArray = null;

                computeThreshold();
                backgroundResizeComplete = true;
                rehashMonitor.notifyAll(); // Kick anyone waiting for the resize to complete...
            }
        }