Skip to content
This repository was archived by the owner on Oct 16, 2022. It is now read-only.

Commit 0cbff23

Browse files
Make use of RecursionSafeAsyncCaller
Add option to TinyAsyncBuilder to make use of RecursionSafeAsyncCaller in front of both the non-threaded caller and threadedCaller
1 parent b829f1d commit 0cbff23

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

tiny-async-core/src/main/java/eu/toolchain/async/TinyAsyncBuilder.java

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
public class TinyAsyncBuilder {
1010
private AsyncCaller caller;
1111
private boolean threaded;
12+
private boolean useRecursionSafeCaller;
1213
private ExecutorService executor;
1314
private ExecutorService callerExecutor;
1415
private ScheduledExecutorService scheduler;
@@ -32,6 +33,24 @@ public TinyAsyncBuilder threaded(boolean threaded) {
3233
return this;
3334
}
3435

36+
/**
37+
* Configure that all caller invocations should use a recursion safe mechanism. In the normal
38+
* case this doesn't change the behaviour of caller and threadedCaller, but when deep recursion
39+
* is detected in the current thread the next recursive call is deferred to a separate thread.
40+
* <p>
41+
* Recursion is tracked for all threads that call the AsyncCallers.
42+
* <p>
43+
* This will make even the non-threaded caller use a thread in the case of deep recursion.
44+
*
45+
* @param useRecursionSafeCaller Set {@code true} if all caller invocations should be done with
46+
* a recursion safe mechanism, {@code false} otherwise.
47+
* @return This builder.
48+
*/
49+
public TinyAsyncBuilder recursionSafeAsyncCaller(boolean useRecursionSafeCaller) {
50+
this.useRecursionSafeCaller = useRecursionSafeCaller;
51+
return this;
52+
}
53+
3554
/**
3655
* Specify an asynchronous caller implementation.
3756
* <p>
@@ -119,11 +138,17 @@ private AsyncCaller setupThreadedCaller(AsyncCaller caller, ExecutorService call
119138
return caller;
120139
}
121140

122-
if (callerExecutor != null) {
123-
return new ExecutorAsyncCaller(callerExecutor, caller);
141+
if (callerExecutor == null) {
142+
return null;
124143
}
125144

126-
return null;
145+
AsyncCaller threadedCaller = new ExecutorAsyncCaller(callerExecutor, caller);
146+
147+
if (useRecursionSafeCaller) {
148+
threadedCaller = new RecursionSafeAsyncCaller(callerExecutor, threadedCaller);
149+
}
150+
151+
return threadedCaller;
127152
}
128153

129154
private ExecutorService setupDefaultExecutor() {
@@ -164,18 +189,28 @@ private ExecutorService setupCallerExecutor(ExecutorService defaultExecutor) {
164189
* @return A caller implementation according to the provided configuration.
165190
*/
166191
private AsyncCaller setupCaller() {
167-
if (caller == null) {
168-
return new PrintStreamDefaultAsyncCaller(
169-
System.err, Executors.newSingleThreadExecutor(new ThreadFactory() {
170-
@Override
171-
public Thread newThread(final Runnable r) {
172-
final Thread thread = new Thread(r);
173-
thread.setName("tiny-async-deferrer");
174-
return thread;
175-
}
176-
}));
192+
if (caller != null) {
193+
if (useRecursionSafeCaller && callerExecutor != null) {
194+
// Wrap user supplied AsyncCaller
195+
return new RecursionSafeAsyncCaller(callerExecutor, caller);
196+
}
197+
return caller;
198+
}
199+
200+
AsyncCaller newCaller = new PrintStreamDefaultAsyncCaller(
201+
System.err, Executors.newSingleThreadExecutor(new ThreadFactory() {
202+
@Override
203+
public Thread newThread(final Runnable r) {
204+
final Thread thread = new Thread(r);
205+
thread.setName("tiny-async-deferrer");
206+
return thread;
207+
}
208+
}));
209+
210+
if (useRecursionSafeCaller && callerExecutor != null) {
211+
newCaller = new RecursionSafeAsyncCaller(callerExecutor, newCaller);
177212
}
178213

179-
return caller;
214+
return newCaller;
180215
}
181216
}

0 commit comments

Comments
 (0)