@SuppressWarnings("unchecked")
  private <E extends Event> void doPost(E e) {
    ListenerBucket<E> b;
    Listener<? super E>[] ls = null;

    Lock l = locks.get(e);
    l.lock();
    try {
      if (retained) {
        if ((b = (ListenerBucket<E>) handlers.get(e)) == null)
          handlers.put(e, b = (ListenerBucket<E>) bucketSupplier.get());
        ls = b.post(e);
      } else {
        if ((b = (ListenerBucket<E>) handlers.get(e)) != null) {
          ls = b.post(e);
          if (b.isEmpty()) handlers.remove(e);
        }
      }
    } finally {
      l.unlock();
    }

    if (ls != null) {
      for (Listener<? super E> li : ls) {
        try {
          li.execute(e);
        } catch (RejectedExecutionException ex) {
          Log.get().postSevere("Event listener rejected! Did the executor shut down?", ex);
        }
      }
    }
  }
  /**
   * Registers the specified event listener.
   *
   * @param e The event to listen for.
   * @param l The event listener.
   * @throws NullPointerException if either argument is null.
   */
  protected final <E extends Event> void doAddListener(E e, Listener<? super E> li) {
    Objects.requireNonNull(li);
    Lock l = locks.get(e);
    l.lock();
    try {
      if (handlers.computeIfAbsent(e, k -> bucketSupplier.get()).addListener(li)) return;
    } finally {
      l.unlock();
    }

    // No return = listener rejected = we should execute it now
    li.execute(e);
  }
  /**
   * Removes an event listener, if it exists.
   *
   * <p>Note that this method generally does not interact nicely with lambdas as they aren't
   * designed for equality testing. As such, when using this method, ensure you're properly
   * unregistering a listener!
   *
   * @param e The event being listened for.
   * @param handler The handler to remove.
   * @throws NullPointerException if either argument is null.
   */
  public <E extends Event> void removeListener(E e, EventHandler<? super E> handler) {
    Objects.requireNonNull(handler);

    Lock l = locks.get(e);
    l.lock();
    try {
      ListenerBucket<?> b = handlers.get(e);
      if (b != null) {
        b.removeListener(li -> li.handler.equals(handler));
        if (b.isEmpty()) handlers.remove(e);
      }
    } finally {
      l.unlock();
    }
  }
 /**
  * Clears any listeners satisfying the specified predicate. This is exposed for subclasses to
  * utilise if they wish; however it is not a part of the public API for obvious reasons.
  *
  * @throws NullPointerException if {@code pred} is {@code null}.
  */
 public final void clearListeners(Predicate<Listener<?>> pred) {
   Objects.requireNonNull(pred);
   handlers
       .entrySet()
       .removeIf(
           e -> {
             Lock l = locks.get(e.getKey());
             l.lock();
             try {
               ListenerBucket<?> b = e.getValue();
               b.removeListeners(pred);
               return b.isEmpty();
             } finally {
               l.unlock();
             }
           });
 }