Skip to content

Commit 13d043c

Browse files
committed
Adding overload of CompletableTask.asyncOn that let specify inheritable default executor
1 parent 68084c3 commit 13d043c

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

src/main/java/net/tascalate/concurrent/CompletableTask.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.concurrent.TimeUnit;
2424
import java.util.function.Supplier;
2525

26+
import net.tascalate.concurrent.decorators.ExecutorBoundPromise;
27+
2628
/**
2729
*
2830
* Concrete implementation of {@link Promise} interface for long-running blocking tasks
@@ -108,6 +110,59 @@ public static Promise<Void> asyncOn(Executor executor) {
108110
return complete(null, executor);
109111
}
110112

113+
/**
114+
* Returns a resolved no-value {@link Promise} that is "bound" to the specified executor.
115+
* I.e. any function passed to composition methods of Promise (like <code>thenApplyAsync</code>
116+
* / <code>thenAcceptAsync</code> / <code>whenCompleteAsync</code> etc.) will be executed using this executor
117+
* unless executor is overridden via explicit composition method parameter. Moreover, any nested
118+
* composition calls will use same executor, if it’s not redefined via explicit composition method parameter:
119+
* {@code}<pre>CompletableTask
120+
* .asyncOn(myExecutor)
121+
* .thenApplyAsync(myValueGenerator)
122+
* .thenAcceptAsync(myConsumer)
123+
* .thenRunAsync(myAction)
124+
* </pre>
125+
* <p>All of <code>myValueGenerator</code>, <code>myConsumer</code>, <code>myActtion</code> will be executed using <code>myExecutor</code>.
126+
* <p>Moreover, if <code>enforceDefaultAsync</code> is true, then default executor will be propagated to dependent promises
127+
* even if corresponding transition was executed on another executor (via composition methods with explicit executor argument).
128+
*
129+
* @param executor
130+
* a default {@link Executor} to run functions passed to async composition methods
131+
* (like <code>thenApplyAsync</code> / <code>thenAcceptAsync</code> / <code>whenCompleteAsync</code> etc.)
132+
* @param enforceDefaultAsync
133+
* if true then default executor will be propagated to dependent promises
134+
* even if corresponding transition was executed on another executor
135+
* @return
136+
* resolved non-value {@link Promise} bound to the specified executor
137+
*/
138+
public static Promise<Void> asyncOn(Executor executor, boolean enforceDefaultAsync) {
139+
Promise<Void> result = complete(null, executor);
140+
if (enforceDefaultAsync) {
141+
class DefaultAsyncDecorator<T> extends ExecutorBoundPromise<T> {
142+
public DefaultAsyncDecorator(Promise<T> delegate) {
143+
super(delegate, executor);
144+
}
145+
146+
@Override
147+
protected <U> Promise<U> wrap(CompletionStage<U> original) {
148+
return new DefaultAsyncDecorator<>((Promise<U>)original);
149+
}
150+
151+
@Override
152+
public Promise<T> raw() {
153+
// Return self to avoid unrolling further
154+
return this;
155+
}
156+
}
157+
158+
return new DefaultAsyncDecorator<>(result);
159+
} else {
160+
return result;
161+
}
162+
}
163+
164+
165+
111166
/**
112167
* Returns a new {@link Promise} that is asynchronously resolved by a task running in the given executor
113168
* after it runs the given action.

0 commit comments

Comments
 (0)