docs: public boolean compareAndSet(T expectedState, T newState)
      {
          checkState(!Thread.holdsLock(lock), "Can not set state while holding the lock");
          requireNonNull(expectedState, "expectedState is null");
          requireNonNull(newState, "newState is null");
  
          FutureStateChange<T> futureStateChange;
          ImmutableList<StateChangeListener<T>> stateChangeListeners;
          synchronized (lock) {
              if (!state.equals(expectedState)) {
                  return false;
              }
  
              // change to same state is not a change, and does not notify the notify listeners
              if (state.equals(newState)) {
                  return false;
              }
  
              checkState(!isTerminalState(state), "%s can not transition from %s to %s", name, state, newState);
  
              state = newState;
  
              futureStateChange = this.futureStateChange.getAndSet(new FutureStateChange<>());
              stateChangeListeners = ImmutableList.copyOf(this.stateChangeListeners);
  
              // if we are now in a terminal state, free the listeners since this will be the last notification
              if (isTerminalState(state)) {
                  this.stateChangeListeners.clear();
              }
          }
  
          fireStateChanged(newState, futureStateChange, stateChangeListeners);
          return true;
      }