1010import java .util .Objects ;
1111import java .util .UUID ;
1212import java .util .concurrent .CancellationException ;
13+ import java .util .concurrent .CompletableFuture ;
1314import java .util .concurrent .ConcurrentHashMap ;
1415import java .util .concurrent .ExecutionException ;
1516import java .util .concurrent .ExecutorService ;
1617import java .util .concurrent .Executors ;
1718import java .util .concurrent .Future ;
19+ import java .util .concurrent .ThreadLocalRandom ;
1820import java .util .concurrent .TimeUnit ;
1921import java .util .concurrent .TimeoutException ;
2022import java .util .concurrent .atomic .AtomicInteger ;
2426 * also logs the actual result of an invocation before being serialized.
2527 */
2628public class JJavaExecutionControl extends DirectExecutionControl {
29+
30+ // generate a semi-unique thread name prefix for each JVM run for easier detection of
31+ // JJavaExecutionControl-produced threads
32+ private static final String THREAD_NAME_PREFIX = "jjava-exec-"
33+ + ThreadLocalRandom .current ().ints (6 , 'a' , 'z' + 1 ).collect (StringBuilder ::new , StringBuilder ::appendCodePoint , StringBuilder ::append )
34+ + "-" ;
35+
2736 /**
2837 * A special "class name" for a {@link jdk.jshell.spi.ExecutionControl.UserException} such that it may be
2938 * identified after serialization into an {@link jdk.jshell.EvalException} via {@link
3039 * EvalException#getExceptionClassName()}.
3140 */
32- public static final String EXECUTION_TIMEOUT_NAME = "Execution Timeout" ; // Has spaces to not collide with a class name
41+ // Has spaces to not collide with a class name
42+ public static final String EXECUTION_TIMEOUT_NAME = "Execution Timeout" ;
3343
3444 /**
3545 * A special "class name" for a {@link jdk.jshell.spi.ExecutionControl.UserException} such that it may be
@@ -56,7 +66,7 @@ public JJavaExecutionControl(JJavaLoaderDelegate loaderDelegate, long timeoutDur
5666
5767 this .timeoutDuration = timeoutDuration ;
5868 this .timeoutUnit = timeoutDuration > 0 ? Objects .requireNonNull (timeoutUnit ) : TimeUnit .MILLISECONDS ;
59- this .executor = Executors .newCachedThreadPool (r -> new Thread (r , "JJava-executor-" + EXECUTOR_THREAD_ID .getAndIncrement ()));
69+ this .executor = Executors .newCachedThreadPool (r -> new Thread (r , THREAD_NAME_PREFIX + EXECUTOR_THREAD_ID .getAndIncrement ()));
6070 }
6171
6272 /**
@@ -121,7 +131,12 @@ public String toString() {
121131
122132 private Object execute (String id , Method doitMethod ) throws Exception {
123133
124- Future <Object > runningTask = executor .submit (() -> doitMethod .invoke (null ));
134+ // run on the same thread if an execution was called within another execution
135+ boolean alreadyRunByKernel = Thread .currentThread ().getName ().startsWith (THREAD_NAME_PREFIX );
136+ Future <Object > runningTask = alreadyRunByKernel
137+ ? CompletableFuture .completedFuture (doitMethod .invoke (null ))
138+ : executor .submit (() -> doitMethod .invoke (null ));
139+
125140 running .put (id , runningTask );
126141
127142 try {
0 commit comments