code: public T set(T newState)
      {
          checkState(!Thread.holdsLock(lock), "Can not set state while holding the lock");
          requireNonNull(newState, "newState is null");
  
          T oldState;
          FutureStateChange<T> futureStateChange;
          ImmutableList<StateChangeListener<T>> stateChangeListeners;
          synchronized (lock) {
              if (state.equals(newState)) {
                  return state;
              }
  
              checkState(!isTerminalState(state), "%s can not transition from %s to %s", name, state, newState);
  
              oldState = state;
              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 oldState;
      }
docs: Sets the state.
  If the new state does not {@code .equals()} the current state, listeners and waiters will be notified.
  
  @return the old state