Loom Evades Exception Handling
Eric Kolotyluk
eric at kolotyluk.net
Thu Nov 25 22:46:32 UTC 2021
Ahhhhhh..... now I understand the fix...
try (var structuredExecutor =
StructuredExecutor.open("Experiment00", virtualThreadFactory)) {
var completionHandler = new StructuredExecutor.ShutdownOnFailure();
var futureStream = IntStream.range(0, 15).mapToObj(item -> {
System.out.printf("item = %d, Thread ID = %s\n", item,
Thread.currentThread());
return structuredExecutor.fork(() -> {
System.out.printf("\ttask = %d, Thread ID = %s\n",
item, Thread.currentThread());
return item;
}, completionHandler);
});
var futureList = futureStream.toList(); // wait for the
Stream to finish
structuredExecutor.join();
completionHandler.throwIfFailed();
var completedResults =
futureList.stream().map(Future::resultNow).toList();
completedResults.forEach(System.out::println);
System.out.println("Finished Processing");
}
catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
finally {
System.out.println("Finished Finally");
}
Thanks so much, Rémi, that was a really subtle point for me... There was
more concurrency going on than I expected...
We learn more from our failures than our successes...
Cheers, Eric
On Thu, Nov 25, 2021 at 2:25 PM <forax at univ-mlv.fr> wrote:
>
>
> ------------------------------
>
> *From: *"Eric Kolotyluk" <eric at kolotyluk.net>
> *To: *"Remi Forax" <forax at univ-mlv.fr>
> *Cc: *"loom-dev" <loom-dev at openjdk.java.net>
> *Sent: *Jeudi 25 Novembre 2021 23:16:11
> *Subject: *Re: Loom Evades Exception Handling
>
> Thanks for the suggestion Remi, but that does not fix it, it does however
> result in different Exception Handling...
>
> [image: image.png]
>
> Actually, my concern is more about the stack traces, and messages, I
> cannot really pinpoint the root cause of the exception. It's like there is
> missing information about the root cause.
>
> Through another piece of experimental code, I have isolated it to
> something like
>
> structuredExecutor.join();
> completionHandler.throwIfFailed();
> var completedResults = futureResults.map(Future::resultNow).toList();
>
> where the last statement produces
>
> java.lang.IllegalStateException: Task has not completed
> at java.base/java.util.concurrent.FutureTask.resultNow(FutureTask.java:220)
> at
> java.base/java.util.concurrent.StructuredExecutor$FutureImpl.resultNow(StructuredExecutor.java:726)
> at
> java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
> at java.base/java.util.stream.IntPipeline$1$1.accept(IntPipeline.java:180)
> at
> java.base/java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:104)
> at
> java.base/java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:711)
> at
> java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
> at
> java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
> at
> java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
> at
> java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
> at
> java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
> at
> java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
> at
> java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
> at net.kolotyluk.loom.Experiment00.main(Experiment00.java:160)
>
> Which begs the question, how can this throw an exception after the
> previous two statements?
>
>
> Again, a stream delay the calculation so you call fork() when toList is
> called after calling join() not before,
> You have to call toList() before calling throwIfFailed().
>
> For Alan or Ron, fork() should throw an exception if called after join() ?
>
>
> Cheers, Eric
>
>
> Rémi
>
>
>
> On Thu, Nov 25, 2021 at 1:06 PM Remi Forax <forax at univ-mlv.fr> wrote:
>
>> Hi Eric,
>> getRemoteString() returns a Stream, and a Stream delays the call to the
>> intermediary operations to the point where the terminal operation, here
>> forEach(), is called.
>> When forEach() is called, the executor is already closed, so forEach()
>> calls map() that calls fork() that throws an IllegalStateException.
>>
>> I see no issue here, if you return a List instead of a Stream, you will
>> have the behavior I believe you want.
>>
>> regards,
>> Rémi
>>
>> ----- Original Message -----
>> > From: "Eric Kolotyluk" <eric at kolotyluk.net>
>> > To: "loom-dev" <loom-dev at openjdk.java.net>
>> > Sent: Jeudi 25 Novembre 2021 21:27:04
>> > Subject: Loom Evades Exception Handling
>>
>> > Yes, that subject line is click-bait, but this is not intuitive to
>> me... Am
>> > I just seeing an incomplete implementation of Project Loom, and this
>> will
>> > be resolved in the future?
>> >
>> > public class Experiment06 {
>> >
>> > public static void main(String args[]) {
>> > Context.printHeader(Experiment06.class);
>> >
>> > try {
>> > getRemoteStrings().forEach(System.out::println);
>> > } catch (ExperimentException e) {
>> > e.printStackTrace();
>> > }
>> > }
>> >
>> > static Stream<String> getRemoteStrings() throws ExperimentException {
>> >
>> > try (var structuredExecutor =
>> StructuredExecutor.open("Experiment06")) {
>> >
>> > // We want complete results, so we won't tolerate failure.
>> > var completionHandler = new
>> StructuredExecutor.ShutdownOnFailure();
>> >
>> > var futureResults = IntStream.range(0, 15).mapToObj(item -> {
>> > try {
>> > System.out.printf("item = %d, Thread ID = %s\n",
>> > item, Thread.currentThread());
>> > return structuredExecutor.fork(() -> {
>> > try {
>> > System.out.printf("\ttask = %d, Thread ID
>> > = %s\n", item, Thread.currentThread());
>> > return getRemoteString(item, new
>> > URI("https://server1/foobar.com/item"));
>> > }
>> > catch (Throwable t) {
>> > System.out.printf("TASK EXCEPTION
>> > %s\n\t%s\n\n", t.getMessage(), t.getCause());
>> > t.printStackTrace();
>> > throw t;
>> > }
>> > }, completionHandler);
>> > } catch (Throwable t) {
>> > System.out.printf("SPAWN EXCEPTION %s\n\t%s\n\n",
>> > t.getMessage(), t.getCause());
>> > t.printStackTrace();
>> > throw t;
>> > }
>> > });
>> > structuredExecutor.joinUntil(Instant.now().plusSeconds(10));
>> > completionHandler.throwIfFailed();
>> > return futureResults.map(Future::resultNow);
>> > }
>> > catch (InterruptedException e) {
>> > e.printStackTrace();
>> > throw new ExperimentException(e);
>> > } catch (ExecutionException e) {
>> > e.printStackTrace();
>> > throw new ExperimentException(e);
>> > } catch (TimeoutException e) {
>> > e.printStackTrace();
>> > throw new ExperimentException(e);
>> > } catch (IllegalStateException e) {
>> > e.printStackTrace();
>> > throw new ExperimentException(e);
>> > }
>> > catch (Throwable t) {
>> > t.printStackTrace();
>> > throw new ExperimentException(t);
>> > }
>> > }
>> >
>> > static String getRemoteString(int item, URI from) {
>> > return "Item %d from %s".formatted(item, from);
>> > }
>> >
>> > static class ExperimentException extends Exception {
>> > ExperimentException(Throwable cause) {
>> > super(cause);
>> > }
>> > }
>> > }
>> >
>> > where I get
>> >
>> > [image: image.png]
>> >
>> >
>> > (Experiment06.java:50) is
>> >
>> > return structuredExecutor.fork(() -> {
>> >
>> > (Experiment06.java:34) is
>> >
>> > getRemoteStrings().forEach(System.out::println);
>> >
>> > Is there some way I can actually find out more from the Exception
>> handling,
>> > or other techniques?
>> >
>> > Cheers, Eric
>>
>
>
More information about the loom-dev
mailing list