I am trying to understand the structured concurrency (JEP 453) being previewed in current Java 21.
I have this example in which I'm using ShutdownOnSuccess and ShutdownOnFailure.
As mentioned in java docs,
ShutdownOnSuccess captures the first result and shuts down the task scope to interrupt unfinished threads and wakeup the owner. This class is intended for cases where the result of any subtask will do ("invoke any") and where there is no need to wait for results of other unfinished tasks. It defines methods to get the first result or throw an exception if all subtasks fail.
ShutdownOnFailure captures the first exception and shuts down the task scope. This class is intended for cases where the results of all subtasks are required ("invoke all"); if any subtask fails then the results of other unfinished subtasks are no longer needed. If defines methods to throw an exception if any of the subtasks fail.
what I understand is in ShutdownOnSuccess case if one task get completed rest will be interrupted and in
ShutdownOnFailure all task needs to be completed , then shutdown call is made.
So time to complete task assigned in success will be less then failure. is this understanding correct ?
if yes, then time to complete Success is coming greater than failure in every execution, why ?
Here is the sample code.
package com.example.threadex;
import java.time.Duration;
import java.time.Instant;
import java.util.Random;
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Subtask;
public class StructuredTaskScopeExample {
public static void main(String[] args) {
Instant start = Instant.now();
try(var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()){
Subtask<String> task1 = scope.fork(Weather::getTempFromA);
Subtask<String> task2 = scope.fork(Weather::getTempFromB);
Subtask<String> task3 = scope.fork(Weather::getTempFromC);
scope.join();
System.out.println(STR."""
task1: \{task1.state()}: result : \{task1.state() == Subtask.State.SUCCESS ? task1.get() : "Not Available"}
task2: \{task2.state()}: result : \{task2.state() == Subtask.State.SUCCESS ? task2.get() : "Not Available"}
task3: \{task3.state()}: result : \{task3.state() == Subtask.State.SUCCESS ? task3.get() : "Not Available"}
""");
} catch (Throwable e) {
throw new RuntimeException(e);
}
System.out.println(STR."AnySuccess : \{Duration.between(start, Instant.now()).toMillis()}ms");
System.out.println("==================");
Instant start1 = Instant.now();
try(var scope1 = new StructuredTaskScope.ShutdownOnFailure()){
Subtask<String> task1 = scope1.fork(Weather::getTempFromA);
Subtask<String> task2 = scope1.fork(Weather::getTempFromB);
Subtask<String> task3 = scope1.fork(Weather::getTempFromC);
scope1.join();
scope1.throwIfFailed(RuntimeException::new);
System.out.println(STR."""
task1: \{task1.state()}: result: \{task1.get()}
task2: \{task2.state()}: result: \{task2.get()}
task3: \{task3.state()}: result: \{task3.get()}
""");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(STR."AllSuccess : \{Duration.between(start1, Instant.now()).toMillis()}ms");
}
static class Weather{
static Random random = new Random();
public static String getTempFromA(){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return STR."Temp from A: Temp = \{random.nextInt(0, 100)}";
}
public static String getTempFromB(){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return STR."Temp from B: Temp = \{random.nextInt(0, 100)}";
}
public static String getTempFromC(){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return STR."Temp from C: Temp = \{random.nextInt(0, 100)}";
}
}
}
Output i'm getting:
task1: SUCCESS: result : Temp from A: Temp = 57
task2: SUCCESS: result : Temp from B: Temp = 20
task3: SUCCESS: result : Temp from C: Temp = 45
AnySuccess : 57ms
==================
task1: SUCCESS: result: Temp from A: Temp = 78
task2: SUCCESS: result: Temp from B: Temp = 54
task3: SUCCESS: result: Temp from C: Temp = 59
AllSuccess : 18ms
Can anyone explain why this difference ?
Thanks
I didnt work in subtasks but from your description I see that invoke any thread means: just start a task one of them. Invoke All means that start all of them.
So when you think about it one of them is invoking one task and getting first result. Other is invoking all tasks at the same time.