/** Removes a listener for updated cluster states. */
 public void remove(ClusterStateListener listener) {
   clusterStateListeners.remove(listener);
   priorityClusterStateListeners.remove(listener);
   lastClusterStateListeners.remove(listener);
   postAppliedListeners.remove(listener);
   for (Iterator<NotifyTimeout> it = onGoingTimeouts.iterator(); it.hasNext(); ) {
     NotifyTimeout timeout = it.next();
     if (timeout.listener.equals(listener)) {
       timeout.cancel();
       it.remove();
     }
   }
 }
 @Override
 protected synchronized void doStop() {
   for (NotifyTimeout onGoingTimeout : onGoingTimeouts) {
     onGoingTimeout.cancel();
     try {
       onGoingTimeout.cancel();
       onGoingTimeout.listener.onClose();
     } catch (Exception ex) {
       logger.debug("failed to notify listeners on shutdown", ex);
     }
   }
   ThreadPool.terminate(updateTasksExecutor, 10, TimeUnit.SECONDS);
   // close timeout listeners that did not have an ongoing timeout
   postAppliedListeners
       .stream()
       .filter(listener -> listener instanceof TimeoutClusterStateListener)
       .map(listener -> (TimeoutClusterStateListener) listener)
       .forEach(TimeoutClusterStateListener::onClose);
   remove(localNodeMasterListeners);
 }