@@ -190,13 +190,20 @@ public final void addListener(ActionListener<T> listener) {
190190 * then it will be completed using the given executor. If the subscribing listener is completed immediately then
191191 * this completion happens on the subscribing thread.
192192 * <p>
193- * In other words, if you want to ensure that {@code listener} is completed using a particular executor, then you
194- * must do both of:
193+ * This behaviour may seem complex at first sight, but it is like this to allow callers to ensure that
194+ * {@code listener} is completed using a particular executor much more cheaply than simply always forking the
195+ * completion task to the desired executor. To ensure that {@code listener} is completed using a particular
196+ * executor, do both of the following:
195197 * <ul>
196198 * <li>Pass the desired executor in as {@code executor}, and</li>
197199 * <li>Invoke {@link #addListener} using that executor.</li>
198200 * </ul>
199201 * <p>
202+ * If you really want to fork the completion task to a specific executor in all circumstances, wrap the supplied
203+ * {@code listener} in a {@link ThreadedActionListener} yourself. But do note that this can be surprisingly
204+ * expensive, and it's almost always not the right approach, so it is deliberate that there is no convenient method
205+ * on {@link SubscribableListener} which does this for you.
206+ * <p>
200207 * If {@code executor} rejects the execution of the completion of the subscribing listener then the result is
201208 * discarded and the subscribing listener is completed with a rejection exception on the thread which completes
202209 * this listener.
@@ -487,13 +494,19 @@ public <U> SubscribableListener<U> andThen(CheckedBiConsumer<ActionListener<U>,
487494 * The threading of the {@code nextStep} callback is the same as for listeners added with {@link #addListener}: if this listener is
488495 * already complete then {@code nextStep} is invoked on the thread calling {@link #andThen} and in its thread context, but if this
489496 * listener is incomplete then {@code nextStep} is invoked using {@code executor}, in a thread context captured when {@link #andThen}
490- * was called. In other words, if you want to ensure that {@code nextStep} is invoked using a particular executor, then you must do
491- * both of:
497+ * was called. This behaviour may seem complex at first sight but it is like this to allow callers to ensure that {@code nextStep} runs
498+ * using a particular executor much more cheaply than simply always forking its execution. To ensure that {@code nextStep} is invoked
499+ * using a particular executor, do both of the following:
492500 * <ul>
493501 * <li>Pass the desired executor in as {@code executor}, and</li>
494502 * <li>Invoke {@link #andThen} using that executor.</li>
495503 * </ul>
496504 * <p>
505+ * If you really want to fork the execution of the next step in the sequence to a specific executor in all circumstances, explicitly
506+ * call {@link Executor#execute} within {@code nextStep} yourself. But do note that this can be surprisingly expensive, and it's almost
507+ * always not the right approach, so it is deliberate that there is no convenient method on {@link SubscribableListener} which does this
508+ * for you.
509+ * <p>
497510 * If {@code executor} rejects the execution of {@code nextStep} then the result is discarded and the returned listener is completed
498511 * with a rejection exception on the thread which completes this listener. Likewise if this listener is completed exceptionally but
499512 * {@code executor} rejects the execution of the completion of the returned listener then the returned listener is completed with a
0 commit comments