code: protected <T> void dispatchEvent(DispatchQueueSelector queueSelector, List<T> listeners, Consumer<T> consumer) {
          api.getThreadPool().getSingleThreadExecutorService("Event Dispatch Queues Manager").submit(() -> {
              if (queueSelector != null) { // Object dependent listeners
                  // Don't allow adding of more events while there are unfinished object independent tasks
                  Queue<Runnable> objectIndependentQueue = queuedListenerTasks.get(null);
                  while (!objectIndependentQueue.isEmpty()) {
                      try {
                          synchronized (queuedListenerTasks) {
                              // Just to be on the safe side, we use a timeout of 5 seconds
                              queuedListenerTasks.wait(5000);
                          }
                      } catch (InterruptedException ignored) { }
                  }
              }
              Queue<Runnable> queue = queuedListenerTasks.computeIfAbsent(
                      queueSelector, o -> new ConcurrentLinkedQueue<>());
              listeners.forEach(listener -> queue.add(() -> consumer.accept(listener)));
              checkRunningListenersAndStartIfPossible(queueSelector);
          });
      }
docs: Dispatches an event to the given listeners using the provided consumer.
  Calling this method usually looks like this:
  {@code dispatchEvent(server, listeners, listener -> listener.onXyz(event));}
  
  @param queueSelector The object which is used to determine in which queue the event should be dispatched. Usually
  the object is a server object (for server-dependent events), a discord api instance (for
  server-independent events, like DMs or GMs) or {@code null} (for lifecycle events, like
  connection lost, resume or reconnect). Providing {@code null} means, that already started
  dispatchings are going to be finished, then all events with a {@code null} queue selector
  are dispatched and finally other events are dispatched like normal again. Events with the
  same queue selector are dispatched sequentially in the correct order of enqueueal, but on
  arbitrary threads from a thread pool. Events with different queue selectors are dispatched
  in parallel.
  @param listeners     A list with listeners which get consumed by the given consumer.
  @param consumer      A consumer which consumes all listeners from the given list and is meant to call their
  {@code onXyz(Event)} method.
  @param <T>           The type of the listener.