-
Bug
-
Resolution: Not an Issue
-
P3
-
None
-
25
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
Eclipse Temurin 25
A DESCRIPTION OF THE PROBLEM :
I encountered an issue with Structured Concurrency (JEP 505, Fifth Preview) in Java 25.
When a StructuredTaskScope is configured with a timeout factory (cf.withTimeout(...)) and the scope times out, scope.join() correctly throws a StructuredTaskScope.TimeoutException. However, after catching this exception, attempting to retrieve the result of a successfully completed Subtask via subtask.get() unexpectedly throws an IllegalStateException: join not called.
The expected behavior is that even after a scope timeout, the results of subtasks that completed successfully before the deadline should be retrievable. Subtasks that did not complete should be in the UNAVAILABLE state.
I am also aware of the issue JDK-8367858, which is targeted for the Sixth Preview. However, I am unable to determine if the issue I am reporting is related to it or if it has already been resolved by that fix, as I am reporting this based on the Fifth Preview.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile and run the provided Java code (javac --release 25 --enable-preview Main.java).
2. The program will print that it has caught a TimeoutException.
3. It will then throw an IllegalStateException when checking the results of the subtasks.
package org.example;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.StructuredTaskScope;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = StructuredTaskScope.open(
StructuredTaskScope.Joiner.<String>awaitAll(),
cf -> cf.withTimeout(Duration.ofSeconds(5)))) {
List<StructuredTaskScope.Subtask<String>> tasks = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
final int a = i;
final StructuredTaskScope.Subtask<String> t = scope.fork(() -> {
// Use a longer sleep duration to ensure timeout
Thread.sleep(Duration.ofSeconds(a));
return "task" + a;
});
tasks.add(t);
}
try {
System.out.println("begin scope.join()");
scope.join();
} catch (StructuredTaskScope.TimeoutException e) {
System.out.println("caught TimeoutException");
}
System.out.println("check results of subtasks");
for (StructuredTaskScope.Subtask<String> t: tasks) {
switch (t.state()) {
case StructuredTaskScope.Subtask.State.SUCCESS:
// This line throws the exception
final String s = t.get();
System.out.println("success: " + s);
break;
case StructuredTaskScope.Subtask.State.FAILED:
System.out.println("failed: " + t.exception().getMessage());
break;
case StructuredTaskScope.Subtask.State.UNAVAILABLE:
System.out.println("unavailable");
break;
}
}
}
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Example of expected output:
begin scope.join()
caught TimeoutException
check results of subtasks
success: task0
success: task1
success: task2
success: task3
success: task4
unavailable
unavailable
unavailable
unavailable
unavailable
unavailable
The program should not throw an IllegalStateException. It should print the state and result of each subtask. Subtasks that finished within the 5-second timeout should be in the SUCCESS state, and their results should be printed. Subtasks that did not finish should be in the UNAVAILABLE state.
ACTUAL -
begin scope.join()
caught TimeoutException
check results of subtasks
Exception in thread "main" java.lang.IllegalStateException: join not called
at java.base/java.util.concurrent.StructuredTaskScopeImpl.ensureJoinedIfOwner(StructuredTaskScopeImpl.java:127)
at java.base/java.util.concurrent.StructuredTaskScopeImpl$SubtaskImpl.get(StructuredTaskScopeImpl.java:358)
at org.example.Main.main(Main.java:33)
The program throws java.lang.IllegalStateException: join not called when t.get() is invoked on a subtask that should have completed successfully (e.g., the task with a 0-second sleep).
Additional Notes
As a test, I tried adding another scope.join() call inside the catch (StructuredTaskScope.TimeoutException e) block. This resulted in a different exception: java.lang.IllegalStateException: Already joined or scope is closed. This indicates that the scope is indeed considered "joined" after the timeout, which makes the original "join not called" exception seem contradictory and likely a bug.
// ...
} catch (StructuredTaskScope.TimeoutException e) {
System.out.println("caught TimeoutException");
scope.join(); // Adding this line
}
//...
Output with the extra join() call:
begin scope.join()
caught TimeoutException
Exception in thread "main" java.lang.IllegalStateException: Already joined or scope is closed
at java.base/java.util.concurrent.StructuredTaskScopeImpl.ensureNotJoined(StructuredTaskScopeImpl.java:117)
at java.base/java.util.concurrent.StructuredTaskScopeImpl.join(StructuredTaskScopeImpl.java:237)
at org.example.Main.main(Main.java:28)
Eclipse Temurin 25
A DESCRIPTION OF THE PROBLEM :
I encountered an issue with Structured Concurrency (JEP 505, Fifth Preview) in Java 25.
When a StructuredTaskScope is configured with a timeout factory (cf.withTimeout(...)) and the scope times out, scope.join() correctly throws a StructuredTaskScope.TimeoutException. However, after catching this exception, attempting to retrieve the result of a successfully completed Subtask via subtask.get() unexpectedly throws an IllegalStateException: join not called.
The expected behavior is that even after a scope timeout, the results of subtasks that completed successfully before the deadline should be retrievable. Subtasks that did not complete should be in the UNAVAILABLE state.
I am also aware of the issue JDK-8367858, which is targeted for the Sixth Preview. However, I am unable to determine if the issue I am reporting is related to it or if it has already been resolved by that fix, as I am reporting this based on the Fifth Preview.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile and run the provided Java code (javac --release 25 --enable-preview Main.java).
2. The program will print that it has caught a TimeoutException.
3. It will then throw an IllegalStateException when checking the results of the subtasks.
package org.example;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.StructuredTaskScope;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = StructuredTaskScope.open(
StructuredTaskScope.Joiner.<String>awaitAll(),
cf -> cf.withTimeout(Duration.ofSeconds(5)))) {
List<StructuredTaskScope.Subtask<String>> tasks = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
final int a = i;
final StructuredTaskScope.Subtask<String> t = scope.fork(() -> {
// Use a longer sleep duration to ensure timeout
Thread.sleep(Duration.ofSeconds(a));
return "task" + a;
});
tasks.add(t);
}
try {
System.out.println("begin scope.join()");
scope.join();
} catch (StructuredTaskScope.TimeoutException e) {
System.out.println("caught TimeoutException");
}
System.out.println("check results of subtasks");
for (StructuredTaskScope.Subtask<String> t: tasks) {
switch (t.state()) {
case StructuredTaskScope.Subtask.State.SUCCESS:
// This line throws the exception
final String s = t.get();
System.out.println("success: " + s);
break;
case StructuredTaskScope.Subtask.State.FAILED:
System.out.println("failed: " + t.exception().getMessage());
break;
case StructuredTaskScope.Subtask.State.UNAVAILABLE:
System.out.println("unavailable");
break;
}
}
}
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Example of expected output:
begin scope.join()
caught TimeoutException
check results of subtasks
success: task0
success: task1
success: task2
success: task3
success: task4
unavailable
unavailable
unavailable
unavailable
unavailable
unavailable
The program should not throw an IllegalStateException. It should print the state and result of each subtask. Subtasks that finished within the 5-second timeout should be in the SUCCESS state, and their results should be printed. Subtasks that did not finish should be in the UNAVAILABLE state.
ACTUAL -
begin scope.join()
caught TimeoutException
check results of subtasks
Exception in thread "main" java.lang.IllegalStateException: join not called
at java.base/java.util.concurrent.StructuredTaskScopeImpl.ensureJoinedIfOwner(StructuredTaskScopeImpl.java:127)
at java.base/java.util.concurrent.StructuredTaskScopeImpl$SubtaskImpl.get(StructuredTaskScopeImpl.java:358)
at org.example.Main.main(Main.java:33)
The program throws java.lang.IllegalStateException: join not called when t.get() is invoked on a subtask that should have completed successfully (e.g., the task with a 0-second sleep).
Additional Notes
As a test, I tried adding another scope.join() call inside the catch (StructuredTaskScope.TimeoutException e) block. This resulted in a different exception: java.lang.IllegalStateException: Already joined or scope is closed. This indicates that the scope is indeed considered "joined" after the timeout, which makes the original "join not called" exception seem contradictory and likely a bug.
// ...
} catch (StructuredTaskScope.TimeoutException e) {
System.out.println("caught TimeoutException");
scope.join(); // Adding this line
}
//...
Output with the extra join() call:
begin scope.join()
caught TimeoutException
Exception in thread "main" java.lang.IllegalStateException: Already joined or scope is closed
at java.base/java.util.concurrent.StructuredTaskScopeImpl.ensureNotJoined(StructuredTaskScopeImpl.java:117)
at java.base/java.util.concurrent.StructuredTaskScopeImpl.join(StructuredTaskScopeImpl.java:237)
at org.example.Main.main(Main.java:28)
- relates to
-
JDK-8340343 JEP 505: Structured Concurrency (Fifth Preview)
-
- Closed
-
-
JDK-8367858 Implement JEP 525: Structured Concurrency (Sixth Preview)
-
- Provisional
-