Slide 1

Slide 1 text

Programmation Concurrente et Asynchrone State of Loom in the JDK 21 José Paumard Java Developer Advocate Java Platform Group

Slide 2

Slide 2 text

https://twitter.com/JosePaumard https://github.com/JosePaumard https://www.youtube.com/c/JosePaumard01 https://www.youtube.com/user/java https://www.youtube.com/hashtag/jepcafe https://fr.slideshare.net/jpaumard https://www.pluralsight.com/authors/jose- paumard https://dev.java

Slide 3

Slide 3 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 3 https://dev.java/

Slide 4

Slide 4 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 4 Tune in! Inside Java Newscast JEP Café Dev.java Inside.java Inside Java Podcast Sip of Java Cracking the Java coding interview

Slide 5

Slide 5 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 5 https://inside.java/podcast/

Slide 6

Slide 6 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | Confidential: Internal/Restricted/Highly Restricted 6 Loom

Slide 7

Slide 7 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 7 Adoption ?

Slide 8

Slide 8 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 8 What is wrong with this code? Concurrency Issues ExecutorService es = ...; Future f1 = es.submit(SomeService::readImage); Future f2 = es.submit(SomeService::readName); Page page = new Page(f1.get(), f2.get());

Slide 9

Slide 9 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 9 What is wrong with this code? Concurrency Issues Json request = buildContractRequest(id); String contractJson = contractServer.getContract(request); Contract contract = Json.unmarshal(contractJson);

Slide 10

Slide 10 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 10 What is wrong with this code? Concurrency Issues Contract contract = CompletableFuture.async( () -> buildContractRequest(id)) .thenApply( ContractServer::getContract) .exceptionnaly( exception -> doSomethingWith(exception)) .thenApply( Json::unmarshall).get();

Slide 11

Slide 11 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 11 What is wrong with this code? Concurrency Issues ExecutorService es = ...; Future f1 = es.submit(SomeService::readImage); Future f2 = es.submit(SomeService::readName); Page page = new Page(f1.get(), f2.get());

Slide 12

Slide 12 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 12 Processing I/O data: A Thread is idle 99.9999% of the time! How many threads do you need to keep your CPU busy? Concurrency for I/O ms ns ns

Slide 13

Slide 13 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 13 Loom fixes two things: - blocking a thread is not an issue anymore  Virtual threads - in case of exceptions, no more loose thread  Structured Concurrency Concurrency Issues

Slide 14

Slide 14 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 14 Using Virtual Threads ExecutorService service = Executors.newVirtualThreadPerTaskExecutor(); Thread virtuaThread = Thread.ofVirtual() .name("Virtual thread") .start(runnable);

Slide 15

Slide 15 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 15 A Virtual Thread runs on a Carrier Thread How Does it Work? heap Worker 1 start() Virtual thread fork join pool

Slide 16

Slide 16 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 16 When it blocks, the stack to the heap How Does it Work? heap start() blocked! Virtual thread Worker 1 fork join pool

Slide 17

Slide 17 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 17 Continuation.yield() copies the stack in the heap How Does it Work? heap start() blocked! yield() Virtual thread Worker 1 fork join pool

Slide 18

Slide 18 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 18 …until the OS signals that the data is available How Does it Work? heap start() Virtual thread Worker 1 fork join pool

Slide 19

Slide 19 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 19 … at which point Continuation.run() is called How Does it Work? heap start() Virtual thread run() Worker 1 fork join pool

Slide 20

Slide 20 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 20 Which mounts the virtual thread on a platform thread again How Does it Work? heap start() Virtual thread Worker 1 fork join pool

Slide 21

Slide 21 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 21 Which mounts the virtual thread on a platform thread again How Does it Work? heap Virtual thread ? Worker 1 fork join pool Worker 2

Slide 22

Slide 22 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 22 A virtual thread is a thread - Race conditions, visibility, locking, … are the same Loom: Virtual Threads (21) A Platform thread: - takes ~1ms to start - consumes ~2MB - context switching ~0,1ms A Virtual thread: - takes ~1ms to start - consumes ~200kB Blocking a Virtual Thread is OK!

Slide 23

Slide 23 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 23 With Loom’s virtual threads: - Launching a thread is cheap (having 1M is fine), no need to pool them anymore - Blocking a thread is cheap, no need to write non- blocking asynchronous code Loom: Virtual Threads (21)

Slide 24

Slide 24 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 24 The Travel Agency Example Quotation Weather Forecast Travel Page

Slide 25

Slide 25 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 25 Asynchronous Code var quotationCF = CompletableFuture.supplyAsync(() -> getQuotation()); var weatherCF = CompletableFuture.supplyAsync(() -> getWeather()); CompletableFuture travelPageCF = quotationCF .exceptionally(t -> { weatherCF.cancel(true); throw new RuntimeException(t); }) .thenCompose( quotation -> weatherCF // .completeOnTimeout(Weather.UNKNOWN, 100, MILLISECONDS) .exceptionally(e -> Weather.UNKNOWN) .thenApply( weather -> buildPage(quotation, weather)));

Slide 26

Slide 26 text

Quotation Server A 7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 26 The Travel Agency Example Quotation Server B Quotation Server C Weather Forecast Server A Weather Forecast Server B Weather Forecast Server C Travel Agency

Slide 27

Slide 27 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 27 Stuctured Concurrency Based Travel Agency try (var scope = new WeatherScope()) { scope.fork(() -> readWeatherFromA()); scope.fork(() -> readWeatherFromB()); scope.fork(() -> readWeatherFromC()); scope.join(); Weather firstWeather = scope.getFirstWeather(); return firstWeather; }

Slide 28

Slide 28 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 28 Stuctured Concurrency Based Travel Agency try (var scope = new QuotationScope()) { scope.fork(() -> readQuotationFromA()); scope.fork(() -> readQuotationFromB()); scope.fork(() -> readQuotationFromC()); scope.join(); Quotation bestQuotation = scope.getBestQuotation(); return bestQuotation; }

Slide 29

Slide 29 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 29 Stuctured Concurrency Based Travel Agency try (var scope = new TravelPageScope()) { scope.fork(() -> getFirstWeather()); scope.fork(() -> getBestQuotation()); scope.join(); TravelPage page = scope.buildTravelPage(); return page; }

Slide 30

Slide 30 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 30 Stuctured Concurrency Based Travel Agency protected void handleComplete(Subtask task) { switch (task.state()) { case RUNNING -> throw new IllegalStateException("Ooops"); case SUCCESS -> this.quotations.add(task.resultNow()); case FAILED -> this.exceptions.add(task.exceptionNow()); }

Slide 31

Slide 31 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 31 Stuctured Concurrency Based Travel Agency public Quotation bestQuotation() { return this.quotations.stream() .min(Comparator.comparing(Quotation::quotation)) .orElseThrow(this::exceptions); } public QuotationException exceptions() { QuotationException exception = new QuotationException(); this.exceptions.forEach(exception::addSuppressed); return exception; }

Slide 32

Slide 32 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 32 Closing PageScope closes the other scopes A Scope can Spawn more Scopes PageScope QuotationScope WeatherScope

Slide 33

Slide 33 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 33 So many things… - They are mutable - They may be kept alive forever What is Wrong with ThreadLocal?

Slide 34

Slide 34 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 34 An alternative model for ThreadLocal variables ThreadLocal are supported by virtual threads But you can do better! ScopedValue (prev 21)

Slide 35

Slide 35 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 35 ScopedValues are non-modifiable They are not bound to a particular thread They are bound to a single method call Welcome to ScopedValue! ScopedValue key = new ScopedValue.newInstance(); ScopedValue.where(key, "KEY_1") .run(() -> doSomethingSmart())); ScopedValue.where(key, "KEY_2") .run(() -> doSomethingSmart()) .run(() -> soSomethingSmarter());

Slide 36

Slide 36 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 36 ScopedValues are non-modifiable They are not bound to a particular thread They are bound to a single method call Welcome to ScopedValue! ScopedValue key = new ScopedValue.newInstance(); ScopedValue.where(key, "KEY_1") .run(() -> doSomethingSmart())); ScopedValue.where(key, "KEY_2") .run(() -> doSomethingSmart()) .run(() -> soSomethingSmarter());

Slide 37

Slide 37 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 37 ScopedValues are non-modifiable They are not bound to a particular thread They are bound to a single method call Welcome to ScopedValue! ScopedValue key = new ScopedValue.newInstance(); ScopedValue.where(key, "KEY_1") .run(() -> doSomethingSmart())); ScopedValue.where(key, "KEY_2") .run(() -> doSomethingSmart()) .run(() -> soSomethingSmarter());

Slide 38

Slide 38 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 38 Welcome to ScopedValue! ScopedValues are non-modifiable They are not bound to a particular thread They are bound to a single method call void doSomethingSmart() { if (key.isBound()) { String value = key.get(); ... } else { throw new IllegalStateException("Key is not bound"); } }

Slide 39

Slide 39 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 39 Scoped Values are not transmitted to threads reason: you don’t want loose scoped values They are transmitted to StructuredTaskScope reason: you cant have loose scoped values ScopedValue (prev 21)

Slide 40

Slide 40 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 40 Virtual Threads Have Been Integrated!

Slide 41

Slide 41 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 41 Loom is a Work in Progress

Slide 42

Slide 42 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 42 Loom is a Work in Progress

Slide 43

Slide 43 text

7/12/2023 Copyright © 2021, Oracle and/or its affiliates | 43 Loom is a Work in Progress http://jdk.java.net/loom/

Slide 44

Slide 44 text

Loom is great!

Slide 45

Slide 45 text

Loom is great! and it’s there