@@ -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.
@@ -480,13 +487,19 @@ public <U> SubscribableListener<U> andThen(CheckedBiConsumer<ActionListener<U>,
480487 * The threading of the {@code nextStep} callback is the same as for listeners added with {@link #addListener}: if this listener is
481488 * already complete then {@code nextStep} is invoked on the thread calling {@link #andThen} and in its thread context, but if this
482489 * listener is incomplete then {@code nextStep} is invoked using {@code executor}, in a thread context captured when {@link #andThen}
483- * was called. In other words, if you want to ensure that {@code nextStep} is invoked using a particular executor, then you must do
484- * both of:
490+ * was called. This behaviour may seem complex at first sight but it is like this to allow callers to ensure that {@code nextStep} runs
491+ * using a particular executor much more cheaply than simply always forking its execution. To ensure that {@code nextStep} is invoked
492+ * using a particular executor, do both of the following:
485493 * <ul>
486494 * <li>Pass the desired executor in as {@code executor}, and</li>
487495 * <li>Invoke {@link #andThen} using that executor.</li>
488496 * </ul>
489497 * <p>
498+ * If you really want to fork the execution of the next step in the sequence to a specific executor in all circumstances, explicitly
499+ * call {@link Executor#execute} within {@code nextStep} yourself. But do note that this can be surprisingly expensive, and it's almost
500+ * always not the right approach, so it is deliberate that there is no convenient method on {@link SubscribableListener} which does this
501+ * for you.
502+ * <p>
490503 * If {@code executor} rejects the execution of {@code nextStep} then the result is discarded and the returned listener is completed
491504 * with a rejection exception on the thread which completes this listener. Likewise if this listener is completed exceptionally but
492505 * {@code executor} rejects the execution of the completion of the returned listener then the returned listener is completed with a
0 commit comments