Slide 1

Slide 1 text

Head toward Java 20 and Java 21 KUBOTA Yuji LINE Corporation JJUG CCC 2023/06/04

Slide 2

Slide 2 text

KUBOTA Yuji (@sugarlife) Senior Software Engineer at LINE Corporation, IMF team IMF team = Kafka infrastructure team エンジニアリングの究極的な挑戦の場はここにある Kafkaイン フラを全社に提供するIMFチームの仕事のやりがい: https://logmi.jp/tech/articles/325945 「膨大な量のトラフィックを扱えるLINEの環境は魅力的」 Kafkaスペシャリストが語る仕事の醍醐味: https://engineering.linecorp.com/en/interview/kafka-okada OpenJDK Author / IcedTea committer https://www.docswell.com/user/ykubota 2

Slide 3

Slide 3 text

Java 20 and Java 21 Java/JDK 20 2023/03/21リリース non LTS: LTSかどうかに関係なく商用に耐えうる安定性を検証済 (ML) 7 JEP (JBS) 124 CSRs (JBS) 49 Release Note (JBS) Java/JDK 21 2023/09/19リリース予定、2023/06/08から安定化フェーズ(Rampdown)突入 LTS: Oracleは2年ごとのLTSリリース提唱 (OpenJDK ML) 16 JEP (確定していないのも含む) (JBS) 166 CSRs (JBS) 44 Release Note (JBS) 3

Slide 4

Slide 4 text

アップデートとJEP、CSR、Release Note JEP (JDK Enhancement-Proposal) Java新機能拡張の提案 CSR (Compatibility & Specification Reviews) 非互換性を伴う変更のレビュー(非互換性を伴う変更は出す必要がある) Release Note 厳密な定義(※ 管理手順はめちゃくちゃ厳密に定義されている)はないが動作変更な ど、ユーザが対応・修正する必要がある変更を強調するためのもの JBS (JDK Bug System) 課題管理。JEPやCSRも各々1チケットになっている Project (OpenJDK Project) 特定の成果物を作成するための共同作業。JEPはいずれかのProjectに付属するケー スが多い(=付属しないのもある) 4

Slide 5

Slide 5 text

今日の流れ JDK 20/21で導入されたJEPをProjectごとに紹介 JEPを番号順で説明されるより目的が分かりやすい JDK 20で入ってJDK 21で変更されたAPIや消された機能もあるので、最終的な状態を説 明したほうが無駄がなく分かりやすい 注意事項 JDK 20/21で導入されたJEPがないProjectは原則紹介しない 記載がなければ https://github.com/openjdk/jdk/tree/jdk-21+24 に準拠する JDK 21 build 24 5

Slide 6

Slide 6 text

JEPで導入される機能のフェーズ Incubator (JEP 11): Java APIの試験用モジュール( jdk.incubator )。標準化に向けてフィ ードバックを得て変更しやすいように特別なモジュールにしている。有効にするには --add- modules jdk.incubator.xxx の指定が必要 Preview (JEP 12): Java言語の試験機能。有効にするには --enable-preview の指定が必 要。コンパイル時には --release XX か --source XX の指定も必要( XX はバージョン) Experimental(試験機能): GCやコンパイラなどのランタイムの試験機能。有効にするには機 能ごとのオプション以外に、 -XX:+UnlockExperimentalVMOptions の指定が必要 Standard(標準機能): 上記のテストフェーズを通じて標準機能に昇格した機能。通例2回以上 のバージョンアップを挟んで昇格する(例:Preview -> Second Preview -> Standard)。2回で 確実に昇格するわけではなく、コミュニティからのフィードバックなどを受けて改善が続け られる機能もある 6

Slide 7

Slide 7 text

Project Amber 開発生産性を高めるためのJava言語改善 Record Patterns JDK 20: JEP 432: Record Patterns (Second Preview) JDK 21: JEP 440: Record Patterns Pattern Matching for switch JDK 20: JEP 433: Pattern Matching for switch (Fourth Preview) JDK 21: JEP 441: Pattern Matching for switch String Template JDK 21: JEP 430: String Templates (Preview) Unnamed xxx JDK 21: JEP 443: Unnamed Patterns and Variables (Preview) JDK 21: JEP 445: Unnamed Classes and Instance Main Methods (Preview) 7

Slide 8

Slide 8 text

Record Patterns 目的 instanceof パターンマッチング(JEP 394)のRecord版 if (obj instanceof String s) { /* 定数 s を使った処理 */} 変更点 JDK 20: JEP 432: Record Patterns (Second Preview) ジェネリクスレコードパターン(Generic Record Pattern)の型推論に対応 名前付きレコードパターン対応を削除 拡張for構文対応もあったがJDK 21で削除された JDK 21: JEP 440: Record Patterns 標準機能へ昇格 8

Slide 9

Slide 9 text

使用方法(JDK 21) record Point(int x, int y){} Before if (obj instanceof Point) { Point p = (Point) obj; int x = p.x(); int y = p.y(); System.out.println(x+y); } After if (obj instanceof Point(int x, int y)) { // x とy のスコープはこの中だけ System.out.println(x+y); } 9

Slide 10

Slide 10 text

Generic Record Pattern record Box(T t) {} static void print(Box> html) { if (html instanceof Box>(Box(var s))) { System.out.println("Text: " + s); } } 10

Slide 11

Slide 11 text

Pattern Matching for switch 目的 switch 式・文でパターンマッチできるようにし、シンプルかつ安全に記述可能にする 11

Slide 12

Slide 12 text

変更点 JDK 20: JEP 433: Pattern Matching for switch (Fourth Preview) labelにenumを利用している際、実行時に網羅されていない場合のExceptionが IncompatibleClassChangeError から MatchException に変わった IncompatibleClassChangeError はsealedクラスの移行互換性がない場合に 示される。例:sealedクラスの許容されたサブクラスのセットからクラスが削除 され、削除されたクラスの既存バイナリがロードされると出る switch labelの構文を簡素化 ジェネリクスレコードパターンの型推論に対応 JDK 21: JEP 441: Pattern Matching for switch 読み易さのために導入されていたカッコつきパターン対応の削除 Qualified enum定数をcase定数として使用可能に 標準機能へ昇格 12

Slide 13

Slide 13 text

使用方法(JDK 21) Before if (obj instanceof Integer) { return String.format("Your input is number: %d", (Integer)obj); } else if (obj instanceof Double) { : After return switch (obj) { case Integer i -> String.format("int %d", i); case Double d -> ... : } 13

Slide 14

Slide 14 text

String message(Object o) { return switch(o) { case Integer i -> String.format("Your input is number: %d", i); case Double d -> throw new IllegalStateException("Invalid Double argument"); case String s when (s.length() >= 1) -> s; case String s -> "empty message"; // null のハンドリングもサポート ( ない場合はNullPointerException が発生する) case null -> "null"; // この書き方はNG になった // case null, Double d -> "Double or null"; // (Object の継承クラス全部列挙は現実的に不可能なので) default 節がないと // "Incomplete" 「すべての可能な入力値をカバーしていません」でエラー default -> o.toString(); }; } 14

Slide 15

Slide 15 text

正常処理とthrow exception case Integer i -> String.format("Your input is number: %d", i); case Double d -> throw new IllegalStateException("Invalid Double argument"); jshell> message(1) $2 ==> "Your input is number: 1" jshell> message(2.4) | 例外java.lang.IllegalStateException: Invalid Double argument | at message (#12:4) | at (#13:1) 15

Slide 16

Slide 16 text

条件処理 case String s when (s.length() >= 1) -> s; case String s -> "empty message"; jshell> message(null) $4 ==> "null" jshell> message("hoge") $5 ==> "hoge" jshell> message("") $6 ==> "empty message" 16

Slide 17

Slide 17 text

nullハンドリングと網羅性 // null のハンドリングもサポート ( ない場合はNullPointerException が発生する) case null -> "null"; // (Object の継承クラス全部列挙は現実的に不可能なので) default 節がないと // "Incomplete" 「すべての可能な入力値をカバーしていません」でエラー default -> o.toString(); null のハンドリングがなければNPEが発生する jshell> message(null) | 例外java.lang.NullPointerException | at Objects.requireNonNull (Objects.java:233) | at message (#1:2) | at (#2:1) default 節がないと網羅しておらずエラー | エラー: | switch 式がすべての可能な入力値をカバーしていません | return switch(o) { | ^----------... 17

Slide 18

Slide 18 text

Qualified enum label enum Flag { A, B } switch (f) { // Before case A: case B: // After // 以前は"case label must be the unqualifed name" とコンパイルエラー case Flag.A: case Flag.B: } 18

Slide 19

Slide 19 text

JEP 430: String Templates (Preview) JDK 21で初Proposal (Implementation) 目的 // 読みづらい String s = x + " plus " + y + " equals " + (x + y); // 細かすぎる s = new StringBuilder() .append(x) .append(" plus ") .append(y) .append(" equals ") .append(x + y) .toString(); // 引数の数や型の不一致を招きやすい s = String.format("%2$d plus %1$d equals %3$d", x, y, x + y); s = "%2$d plus %1$d equals %3$d".formatted(x, y, x + y); // 独特すぎる MessageFormat mf = new MessageFormat("{0} plus {1} equals {2}"); s = mf.format(x, y, x + y); 19

Slide 20

Slide 20 text

使用方法(JDK 21) JDK 21から導入された java.lang.StringTemplate.Processor を利用する var x = 10.0 var y = 20.5 // built-in processor "STR" // \{ で始まり } で閉じる String s = STR."\{ x } plus \{ y } equals \{ x + y }" s ==> "10.0 plus 20.5 equals 30.5" Text Block s = STR.""" \{ x } plus \{ y } equals \{ x + y} """; s ==> "10.0\n plus\n20.5\n equals\n30.5\n" 20

Slide 21

Slide 21 text

Formatter StringTemplate.Processor の1実装である java.util.FormatProcessor を利用 FormatProcessor.FMT."%2.1f\{ x } plus %2.2f\{ y } equals %.3f\{ x + y }" $1 ==> "10.0 plus 20.50 equals 30.500" // 16 進 var x = 10 var y = 20 FormatProcessor.FMT."0x%04x\{x} + 0x%04x\{y} = 0x%04x\{x + y}" $2 ==> "0x000a + 0x0014 = 0x001e" 21

Slide 22

Slide 22 text

Advanced usage StringTemplate.Processor JSON = StringTemplate.Processor.of( // 単純にJsonObject を作成して返しているがValidation 処理を加えたりもできる (StringTemplate st) -> new JsonObject(st.interpolate()) ); String name = "Joan Smith"; String phone = "555-123-4567"; String address = "1 Maple Drive, Anytown"; // Template 形式でString を書きつつJsonObject を作成する JsonObject doc = JSON.""" { "name": "\{name}", "phone": "\{phone}", "address": "\{address}" }; """; 22

Slide 23

Slide 23 text

JEP 443: Unnamed Patterns and Variables (Preview) JDK 21で初Proposal (Implementation) 目的 不要な変数を明確にしたり、不要なネストを排することで読みやすさ・保守性を向上させ る。 使用方法(JDK 21) Java 9で利用禁止になった(*) Underscore _ で表現する (*): JDK-8061549 23

Slide 24

Slide 24 text

Unnamed patterns (variable) OK if (obj instanceof Point(_, int y)) { System.out.println(y); } if (obj instanceof Point(int _, int y)) { System.out.println(y); } switch (o) { case Point(int x, _) -> ... } NG // Type o instanceof _ o instanceof _(int x, int y) case _ 24

Slide 25

Slide 25 text

Unnamed local variables, exception param, lambda param ブロック内のローカル変数宣言文 (JLS 14.4.2) var _ = hoge.inplaceMethod() (※ forなどのブロック内) try-with-resourceのリソース指定 (JLS 14.20.3) try (var _ = ScopedContext.acquire()){ // 獲得したリソースは使わない } for文のヘッダ (JLS 14.14.1, JLS 14.14.2) for (int i=0, _=sideEffect(); i<10; i++){...} for (Integer _: int){...} catchブロックのexception引数 (JLS 14.20) catch (Throwable _) { #ignore } ラムダ式のパラメータ (JLS 15.27.1) ...stream.collect(Collectors.toMap(String::toUpperCase, _ -> "NODATA")) ※ JLS(Java Language Specification)のリンクはJava 20のもの 25

Slide 26

Slide 26 text

https://bugs.openjdk.org/browse/JDK-8309093 jshell> for (int _[] : new int[][]{new int[]{1}, new int[]{2}}) {} jshell> // jdk-21+24 では通ってしまう ( おそらくjdk-21+26 で直る) 26

Slide 27

Slide 27 text

https://bugs.openjdk.org/browse/JDK-8309093 jshell> for (int _[] : new int[][]{new int[]{1}, new int[]{2}}) {} ^^^ これがダメ jshell> // jdk-21+24 では通ってしまう ( おそらくjdk-21+26 で直る) 27

Slide 28

Slide 28 text

JEP 445: Unnamed Classes and Instance Main Methods (Preview) JDK 21から導入開始 目的 クラス、パッケージ、モジュールといった概念はなしでただ実行できるようにして、プログ ラムの基本(変数、分岐、ルーチン等)から段階的に学べるようにする 28

Slide 29

Slide 29 text

使用方法(予定)(JDK 21) 注意: main-line(openjdk/jdk)にマージされていないためまだ確定していない (PR) Before public class Main { public static void main(String[] args) { System.out.println("Hello, World!"); } } After void main() { System.out.println("Hello, World!"); } Source code launcherで実行すればコンパイルすら要らない $ java --source 21 --enable-preview Main.java 29

Slide 30

Slide 30 text

public static void main(String[] args) { System.out.println("old school"); } protected void main(String[] args) { System.out.println("not static"); } protected static void main() { System.out.println("no arguments"); } void main() { System.out.println("minimum"); } 30

Slide 31

Slide 31 text

// 1 public static void main(String[] args) { System.out.println("old school"); } // 3 protected void main(String[] args) { System.out.println("not static"); } // 2 protected static void main() { System.out.println("no arguments"); } // 4 void main() { System.out.println("minimum"); } "old school" -> "no arguments" -> "not static" -> "minimum" アクセス修飾子はprivateでなければOK 31

Slide 32

Slide 32 text

Project Loom 軽量同時実行。軽量スレッドと同時実行性プログラミングモデル Virtual Threads JEP 436: Virtual Threads (Second Preview) JEP 444: Virtual Threads Scoped Values 20: JEP 429: Scoped Values (Incubator) 21: JEP 446: Scoped Values (Preview) Structured Concurrency 20: JEP 437: Structured Concurrency (Second Incubator) 21: JEP 453: Structured Concurrency (Preview) 32

Slide 33

Slide 33 text

Virtual Threads 目的 Javaの並列処理の単位 = スレッド 従来のスレッド(Platform threads) = OSのシステムスレッドのラッパー Platform threadsのボトルネックやスケールのし辛さ 待ち状態 (CPU、同時アクセス、コンテキストスイッチ) 呼び出しや処理切り替えなどのコストが高い システムリソース上限よりOSのスレッド数上限に達するケースがある OSではなくJVMが管理する軽量スレッド(Virtual threads)を導入 33

Slide 34

Slide 34 text

変更点 JDK 20(JEP 436) JDK 19(JEP 425)で提案された内容の一部であるThreadやFutureの新メソッド追 加、ExecutorServiceをAutoCloseableに拡張変更、ThreadGroupのデグレードは 恒久化された(Previewでフィードバックを受ける対象ではなくなった) JDK 21(JEP 444) ThreadLocal変数を常にサポート。この変数を持てないVirtual Threadsは作れなく することで既存ライブラリの移行コストを下げた 標準機能へ昇格 34

Slide 35

Slide 35 text

使用方法(JDK 21) // 従来のPlatform threads jshell> var t = new Thread(() -> System.out.println("platform threads")) t ==> Thread[#25,Thread-0,5,main] jshell> t.start() platform threads // Virtual threads はコンストラクタがない。unstarted() で開始させずに得られる // `ofVirtual()` を`ofPlatform()` にすると従来のPlatform threads が得られる jshell> var t = Thread.ofVirtual().unstarted(() -> System.out.println("virtual threads")) t ==> VirtualThread[#26]/new jshell> t.start() virtual threads 35

Slide 36

Slide 36 text

注意事項 (1/2) JFRやJVM TI、Java Debug InterfaceなどはVirtual threadsに対応済みであるが、一部は互換 性などの都合でPlatform threadsに限定するように修正された Thread.set{Priority,Deamon}(...) はVirtual Threadsには効果がない Virtual threadsはThreadGroupのアクティブメンバーではない。 Thread.getThreadGroup() を呼び出してもダミーの空グループが返る Thread.getAllStackTraces() は全てのスレッドではなくPlatform threadsのみ返す com.sun.management.HotSpotDiagnosticMXBean#dumpThreads が新しく追加 され virtual threadsのダンプも出すようになった 36

Slide 37

Slide 37 text

注意事項 (2/2) JVM TIの GetAllThreads や GetAllStackTraces はVirtual Threadを返さない JVM TI agentが ThreadStart と ThreadEnd イベントを有効にしている場合、 Platform Threadsに限定する機能がないため性能劣化する場合がある java.lang.management.ThreadMXBean はPlatform Threadsだけサポートしている findDeadlockedThreads も当然Platform Threadsのみ Virtual threadsはSecurity Managerが有効だとpermissionがない -XX:+PreserveFramePointer はVirtual Threadsの顕著な性能劣化を引き起こす 37

Slide 38

Slide 38 text

Scoped Values 目的 スレッド内と子スレッドの両方で不変データを共有するプログラミングモデルの提供 とくに大量のVirtuah threadsを使用する場合において、ThreadLocal変数よりも、使い やすさ・理解しやすさ、堅牢性や性能の向上を目指す 38

Slide 39

Slide 39 text

ThreadLocal変数の設計上の欠陥 1. 変更可能性:ThreadLocal変数はいつでも変更可能であり、データフローがスパゲッティ 化し、どのコンポーネントがどの順序で(共有している)状態を更新しているのかが不明瞭 になる可能性がある 2. 長命:ThreadLocal変数はスレッドの寿命が尽きるまで、または remove() メソッドが 呼び出されるまで保持され、しばしば開発者は忘れる(か、1.のせいで複雑すぎて不要に なるタイミングが分からない)ため、メモリリークする可能性がある 3. 継承:親スレッドのThreadLocal変数が子スレッドに継承されるため、多くのスレッド を使う場合にオーバーヘッド(特にメモリ使用量)が増大する可能性がある 39

Slide 40

Slide 40 text

変更点 JDK 20: JEP 429: Scoped Values (Incubator) 提案開始。Incubator( jdk.incubator.concurrent )。 JDK 21: JEP 446: Scoped Values (Preview) まだ確定ではない(Proposed to target) Preview ( java.lang ) へ ScopeValue.where が runWhere , callWhere , getWhere と操作が明確なメソッ ド名に変更 JDK 20では ScopeValue.where(...).run(...) のような書き方だった 40

Slide 41

Slide 41 text

使用方法(予定)(JDK 21) 注意: main-line(openjdk/jdk)にマージされていないためまだ確定していない (PR) private final static ScopedValue USER = ScopedValue.newInstance(); // 引数は ScopedValue のkey, value, Runnable // 渡したRunnable が完了したら即座に解放される ScopedValue.runWhere(USER, new User("duke"), () -> doSomething()); // Before void doSomething(User user){ ... // User に対する処理 } // After void doSomething() { User user = USER.get(); // duke ... // User に対する処理 } 41

Slide 42

Slide 42 text

Rebinding void doSomething() { User user = USER.get(); // duke ... // User に対する処理 // 再バインド (userService から最新のユーザ情報を入手してバインドする例) ScopedValue.runWhere(USER, userService.get(), () -> doAnother() ); // doAnother() が完了すると元の"duke" ユーザにバインドされ直される } void doAnother() { User user = USER.get(); // userService.get() で得たユーザ ... } 42

Slide 43

Slide 43 text

Inheriting Scoped Values // StructuredTaskScope によって生成された子スレッドは、親スレッドのスコープ値にアクセス可能 // ThreadLocal を使用すると、その値が各子スレッドにコピーされる(= メモリがどーん) ScopedValue.runWhere(USER, new User("duke"), () -> { try (var scope = new StructuredTaskScope()) { scope.fork(() -> childTask()); ... } }); String childTask() { User user = USER.get(); // duke ... } 43

Slide 44

Slide 44 text

Structured Concurrency 目的 並列処理を楽にしたい 「タスクをあるコードブロックでサブタスクに分けて同時進行できるようにし、最終的にそ れらは同じコードブロックに戻る」仕組みを提供することで実現 44

Slide 45

Slide 45 text

変更点 JDK 20: JEP 437: Structured Concurrency (Second Incubator) Scoped Values対応 (先ほど説明したInheriting Scoped Values) JDK 21: JEP 453: Structured Concurrency (Preview) まだ確定ではない(Proposed to target) Incubator( jdk.incubator.concurrent )からPreview ( java.util.concurrent ) へ StructuredTaskScope::fork が Future ではなく StructuredTaskScope.Subtask を返すように変更 45

Slide 46

Slide 46 text

使用方法(予定)(JDK 21) 注意: main-line(openjdk/jdk)にマージされていないためまだ確定していない (PR)。前述の Scoped Valueと同じPR // サブタスクで実行させる処理のリスト List> tasks = ... try (var scope = new StructuredTaskScope()) { // scope.fork() によりサブタスクを実行( フォーク) List> subtasks = tasks.stream().map(scope::fork).toList(); // サブタスクの完了を待機 scope.join(); // 成功サブタスクと失敗サブタスクを別セットに分割 Map>> map = subtasks.stream()  .collect(Collectors.partitioningBy( h -> h.state() == Subtask.State.SUCCESS, Collectors.toSet())); } // 全リソースクローズ 46

Slide 47

Slide 47 text

実行中のスレッドいずれかが返ってきたら他をすべてシャットダウン ShutdownOnSuccess を利用する try (var scope = new StructuredTaskScope.ShutdownOnSuccess()) { List> subtasks = tasks.stream().map(scope::fork).toList(); // いずれか一つのサブタスクが成功(Subtask.State#SUCCESS) するか、 // すべて失敗(Subtask.State#FAILED) するまで待つ scope.join(); try { // 最初に成功したサブタスクの結果を取得 String result = scope.result(); ... // 成功したタスクの結果を利用した処理 } catch (ExecutionException e) { // すべて失敗した場合はExecutionException が投げられる throw new CustomException(e); } } 47

Slide 48

Slide 48 text

実行中のスレッドいずれかが例外を出したらすべてシャットダウン ShutdownOnFailure を利用する try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { // 結果が欲しいだけなのでSupplier を使う List> suppliers = tasks.stream().map(scope::fork).toList(); // いずれか一つのサブタスクが失敗するか、すべて成功するか、10 秒経過するまで待つ // (10 秒過ぎたらTimeoutException) Instant deadline = LocalDateTime.now().plusSeconds(10).toInstant(ZoneOffset.UTC); scope.joinUntil(deadline); // 最初に失敗したサブタスクの例外を補足して伝播、終了 scope.throwIfFailed(e -> new CustomException(e)); // 全てのサブタスクが成功した場合の処理 ( サブタスクの結果(String) を並べてるだけ) String result = suppliers.stream() .map(Supplier::get) .collect(Collectors.joining(", ")); } 48

Slide 49

Slide 49 text

スレッドダンプによるObservabilityの向上 Java 19からVirtual ThreadのJEP(JEP 425)でJSONのスレッドダンプ形式が追加された。こ れを使うと StructuredTaskScope のスレッドを階層的にグループ化して表示可能 $ jcmd Thread.dump_to_file -format=json 各スコープのJSONにはそのスコープでフォークされたスレッドとそのスタックトレースが含 まれている。また、各スコープのJSONはその親への参照も持っているのでスレッドダンプか らプログラムの構造を再構築することができる これはJMX( com.sun.management.HotSpotDiagnosticsMXBean#dumpThreads )から取得 することも可能(Java 21から標準機能) Virtual Threadsを用いることでブロッキングが容易になるのはこういった取り組みも含めて という側面もある 49

Slide 50

Slide 50 text

50

Slide 51

Slide 51 text

Project Valhalla 「クラスのように記述でき、intのように動作する」新しい型、Value Objectの導入。参照タ イプとプリミティブタイプを区別しているJavaの型システムのギャップを埋めることで、ボ クシングを不要とした、全ての型を汎用化して使えるようにするプロジェクト JEP draft: Value Objects JEP 401: Flattened Heap Layouts for Value Objects (Preview) JDK 20およびJDK 21で入るJEPはないが次のProject Panamaと関連性が強いため紹介 51

Slide 52

Slide 52 text

Project Panama JVMと外部(Java以外の)ライブラリとのインタラクションを改善、強化するプロジェクト Vector API 20: JEP 438: Vector API (Fifth Incubator) 21: JEP 448: Vector API (Sixth Incubator) Foreign Function & Memory API 20: JEP 434: Foreign Function & Memory API (Second Preview) 21: JEP 442: Foreign Function & Memory API (Third Preview) 52

Slide 53

Slide 53 text

Vector API 目的 SIMD(Single Instruction, Multiple Data, 複数データに対して同じ操作を同時に実行すること を可能にし、1つのCPUサイクルでより多くの計算を実行できる仕組み)演算をサポートする ベクトル演算を実行するためのJava API ベクトル演算を最適なハードウェアレジスタとベクトル命令にコンパイルするC2コンパ イラ 計算爆発しないように様々な演算(単項演算、二項演算、変換演算等)に対応する汎 用化された内部演算を定義 53

Slide 54

Slide 54 text

変更点 JDK 20: JEP 438: Vector API (Fifth Incubator) Bug fixと性能改善のみ JDK 21: JEP 448: Vector API (Sixth Incubator) Buf fixと性能改善のみ 54

Slide 55

Slide 55 text

Project Valhallaとの関り 最終的にはベクタークラスを値クラス(value class)として宣言できるようにしたい。それまで は Vector とそのサブクラスをvalue-based classとして使っている。汎用化が進み、 E はIntegerのようなbox型ではなく、intなどのプリミティブクラスを指定できるようにし、 IntVectorなどの必要性を排して提供する このため、Valhallaが提供されてからPreview APIとして提供する 55

Slide 56

Slide 56 text

使用方法(JDK 21) // c = (a*a + b*b) void vectorComputation(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i += SPECIES.length()) { var m = SPECIES.indexInRange(i, a.length); var va = FloatVector.fromArray(SPECIES, a, i, m); var vb = FloatVector.fromArray(SPECIES, b, i, m); var vc = va.mul(va).add(vb.mul(vb)); vc.intoArray(c, i, m); } } 56

Slide 57

Slide 57 text

Foreign Function & Memory API 目的 以下の既存APIの欠点を克服した「ヒープ外のメモリを直接扱うAPI」を提供する ByteBuffer でDirect Bufferは2GBまででメモリの開放はGCに依存する sun.misc.Unsafe はクラッシュの危険性があることと最終的には廃止させたい JNIはJavaで完結できずCコードを書く必要があり、CとJavaで行き来する必要があるの でオーバーヘッドが発生して性能が良くない 57

Slide 58

Slide 58 text

変更点 かれこれJava 14(JEP 370)からだが(※ Foreign-Memory Access APIからカウント)いま だにbreaking changeが多い JDK 20: JEP 434: Foreign Function & Memory API (Second Preview) MemorySegment と MemoryAddress の使い勝手(abstraction)を統一 sealed MemoryLayout をパターンマッチ(switch)で使いやすくした MemorySession を Arena と SegmentScope に分割 JDK 21: JEP 442: Foreign Function & Memory API (Third Preview) Native Segmentのライフタイム管理を Arena インターフェースに一元化 アドレスレイアウトを日参照にする新要素を追加 短命でJavaサイドに呼ばれない関数の呼び出しを最適化するリンカオプションを追 加 libffi をベースとしたfallback native linkerを提供 VaList クラスを削除 58

Slide 59

Slide 59 text

使用方法(JDK 21) 関連クラスは java.lang.foreign packageにある //strlen で文字列長を出す // ライブラリ準備 (Linker) Linker linker = Linker.nativeLinker(); SymbolLookup stdlib = linker.defaultLookup(); java.lang.invoke.MethodHandle strlen = linker.downcallHandle( stdlib.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS) ); // メモリ準備(malloc) try (Arena arena = Arena.ofConfined()) { MemorySegment cString = arena.allocateUtf8String("Hello, World"); long len = (long)strlen.invokeExact(cString); System.out.println(len); // 12 } // 解放 (free) 詳細な内容はJEP Ownerのポストへ: https://inside.java/u/MaurizioCimadamore/ 59

Slide 60

Slide 60 text

No Project JDK 21: JEP 404: Generational Shenandoah (Experimental) JDK 21: JEP 439: Generational ZGC JDK 21: JEP 431: Sequenced Collections JDK 21: JEP 451: Prepare to Disallow the Dynamic Loading of Agents JDK 21: JEP 449: Deprecate the Windows 32-bit x86 Port for Removal JDK 21: JEP 452: Key Encapsulation Mechanism API 60

Slide 61

Slide 61 text

JDK 21: JEP 404: Generational Shenandoah (Experimental) https://github.com/openjdk/jdk/pull/14185 目的 世代を分けてよりサイクルを回すことで回収効率が改善して以下が見込める (持続的な)メモリ使用量(memory overhead)、CPU・電源使用量の削減 allocation failureによるSTWを要求する余分なGC発生リスクの低減 Degenerated GC: allocation failureとなった場合にSTWを発生させて回収する Full GC: Degeneratedでも十分なメモリが確保できなかった場合等の最終手段 現在はx64とAArch64をサポート。将来的にデフォルトにする方向 使用方法(JDK 21) -XX:ShenandoahGCMode=generational 61

Slide 62

Slide 62 text

JDK 21: JEP 439: Generational ZGC https://github.com/openjdk/jdk/pull/13771 目的 世代別によるメリットはShenandoahと原則一緒。こちらも最終的にメンテナンスコスト削減 のため置き換え予定 JDK 17からZGCでは UseDynamicNumberOfGCThreads を尊重して並行GCスレッド数を調整 してCPU使用量を抑えることができるが、より抑えられる可能性がある 使用方法(JDK 21) -XX:+ZGenerational 62

Slide 63

Slide 63 text

JDK 21: JEP 431: Sequenced Collections 目的 順序(encounter order)を定義するシーケンス型がない 最初|最後の要素取得などの操作がコレクションごとに独自実装で一貫性がない List / Deque -> 順序性はあるがスーパータイプは Collection であり未定義 Set -> 定義がない。一部サブクラスにはある(例: SortedSet / LinkedHashSet ) LinkedHashSet を Collections::unmodifiableSet でラップすると順序の定義 が失われる ということで、順序付き要素のシーケンスを表すインターフェースを追加 63

Slide 64

Slide 64 text

逆順で反復処理する際の書き方 Before // List for (var it = list.listIterator(list.size()); it.hasPrevious();) { var e = it.previous(); ... } // Deque for (var it = deque.descendingIterator(); it.hasNext();) { var e = it.next(); ... } // Set navigableSet.descendingSet().stream()... After everyCollection.reversed().stream()... 64

Slide 65

Slide 65 text

65

Slide 66

Slide 66 text

SequencedCollection 要素が定義された順序を持つコレクション 最初と最後の要素があり、それらの間の要素は、「前の要素」と「後ろの要素」を持つ。 ど ちらの端でも共通の操作をサポートし、要素を最初から最後、最後から最初に処理すること ができる メソッド的にはDequeに reversed() が追加された形 interface SequencedCollection extends Collection { // new method SequencedCollection reversed(); // methods promoted from Deque void addFirst(E); void addLast(E); E getFirst(); E getLast(); E removeFirst(); E removeLast(); } 66

Slide 67

Slide 67 text

67

Slide 68

Slide 68 text

SequencedSet 重複を含まない SequencedCollection の Set SortedSet のように相対比較で要素を配置するコレクションは、 addFirst(E) や addLast(E) のような明示的な配置操作ができないため、 UnsupportedOperationException をスロー interface SequencedSet extends Set, SequencedCollection { SequencedSet reversed(); // covariant override (+ Set) } 68

Slide 69

Slide 69 text

69

Slide 70

Slide 70 text

SequencedMap エントリーが定義された順序を持つ Map メソッド的には NavigableMap に reversed() , sequenced{KeySet,Values,EntrySet} () , put{First,Last}(K, V) が追加された形 put{First,Last}(K, V) は、 LinkedHashMap ではエントリーが既に存在する場合そのエ ントリーを再配置するが、 SortedMap などでは UnsupportedOperationException をスロ ーする 70

Slide 71

Slide 71 text

interface SequencedMap extends Map { // new methods SequencedMap reversed(); SequencedSet sequencedKeySet(); SequencedCollection sequencedValues(); SequencedSet> sequencedEntrySet(); V putFirst(K, V); V putLast(K, V); // methods promoted from NavigableMap Entry firstEntry(); Entry lastEntry(); Entry pollFirstEntry(); Entry pollLastEntry(); } 71

Slide 72

Slide 72 text

新たに追加されたインターフェースは Collections.unmodifiable* も追加された。 ( Collections.unmodifiableSequencedCollection(collection) とか) 既存コードとコンフリクト(名前衝突、共変のオーバライド(継承されたデフォルトメソッドの 実装が異なる)、等)が発生するため、独自で実装していた場合は非互換性対応が必要になるこ とに注意 https://mail.openjdk.org/pipermail/quality-discuss/2023-May/001118.html 72

Slide 73

Slide 73 text

JDK 21: JEP 451: Prepare to Disallow the Dynamic Loading of Agents 未確定(Proposed to target) Integrated (2023-06-02) 目的 Java agent( java.lang.instrument )やJVM TI agentはAttach APIを利用することで動的に 実行中のプロセスにアタッチすることができる。HeapStatsの例(AgentAttacher.java) これはJVMプロセス起動後からクラスの挙動を変えることが可能であり、起動時にオプショ ン( -javaagent や -agentlib )で指定する場合は意図通りであると保証できるが、動的ロー ドはその保証がない。このため、動的ロードの仕組みやAttach APIは消さないが、デフォルト で禁止にして禁止していないことを明示させる形式に変更する 73

Slide 74

Slide 74 text

使用方法 対処方法(予定) 注意: main-line(openjdk/jdk)にマージされていないためまだ確定していない (PR) 発表2日前 にマージされた(commit)。jdk-21+26から有効(予定) -XX:+EnableDynamicAgentLoading で警告を抑制できる どこでアタッチしているか不明な場合は -Djdk.instrument.traceUsage で Instrumentation APIが呼び出された時にスタックトレースを出せる (JVM TIは非対応) 74

Slide 75

Slide 75 text

JDK 21: JEP 449: Deprecate the Windows 32-bit x86 Port for Removal 目的 Windows 32-bit x86 portの廃止 1)Virtual Threadsの対応がつらい 2)32bit対応している最後のOSであるWindows 10が 2025/10月にEoL 使用方法 対処方法 なし(自分でメンテナンスしてビルドする) 75

Slide 76

Slide 76 text

JDK 21: JEP 452: Key Encapsulation Mechanism API 未確定(Proposed to target) Completed (2023-06-02) 目的 量子攻撃などから守るため、共通鍵暗号で利用する秘密鍵を配送するための手段として鍵カ プセル化メカニズムKEM(Key Encapsulation Mechanisms)のAPIを提供する 使用方法(予定)(JDK 21) 注意: main-line(openjdk/jdk)にマージされていないためまだ確定していない (PR) 発表4日前 にマージされた(commit)。jdk-21+25から有効 76

Slide 77

Slide 77 text

"ABC "キーペアを生成し、共通鍵暗号を公開 // Receiver side KeyPairGenerator g = KeyPairGenerator.getInstance("ABC"); KeyPair kp = g.generateKeyPair(); publishKey(kp.getPublic()); 77

Slide 78

Slide 78 text

共通鍵暗号で鍵カプセル化 // Sender side KEM kemS = KEM.getInstance("ABC-KEM"); PublicKey pkR = retrieveKey(); ABCKEMParameterSpec specS = new ABCKEMParameterSpec(...); KEM.Encapsulator e = kemS.newEncapsulator(pkR, null, specS); KEM.Encapsulated enc = e.encapsulate(); SecretKey secS = enc.key(); sendBytes(enc.encapsulation()); sendBytes(enc.params()); 78

Slide 79

Slide 79 text

鍵非カプセル化(decapsulation) // Receiver side byte[] em = receiveBytes(); byte[] params = receiveBytes(); KEM kemR = KEM.getInstance("ABC-KEM"); AlgorithmParameters algParams = AlgorithmParameters.getInstance("ABC-KEM"); algParams.init(params); ABCKEMParameterSpec specR = algParams.getParameterSpec(ABCKEMParameterSpec.class); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), specR); SecretKey secR = d.decapsulate(em); 79

Slide 80

Slide 80 text

Other noteworthy changes Tool (21) JDK-8306704: JFR: Summary views jfr view pinned-threads file.jfr (22) JDK-8308230: JFR: Query views jfr query "select * from GarbageCollection" file.jfr (?) JDK-8284289: JEP 435: Asynchronous Stack Trace VM API Java及びネイティブの両フレームを含むスタックトレースを非同期に取得でき るAPI AsyncGetStackTrace の提供 80

Slide 81

Slide 81 text

GC (G1) (20) JDK-8297247: Add GarbageCollectorMXBean for Remark and Cleanup pause time in G1 (20) JDK-8210708: Use single mark bitmap in G1 マークビットマップの一つを削除してネイティブメモリフットプリントを削減 (ヒープサイズの約1.5%) (20) JDK-8137022: Concurrent refinement thread adjustment and (de-)activation suboptimal Refinement threadの最適化(Remembered Set関連処理) 関連オプション G1ConcRefinement.* , G1UseAdaptiveConcRefinement が廃止された (21) JDK-8225409: G1: Remove the Hot Card Cache Refinementに適したデータ構造だったが、もはや不要なので削除。ネイティブ メモリ削減 (21) JDK-8297639: Remove preventive GCs in G1 Evacuation failedに殆ど寄与しない状況になったので削除 81

Slide 82

Slide 82 text

Security (20) JDK-8155246: Throw error if default java.security file is missing 指定したファイルがなければ実行時に InternalError が発生する (20) JDK-8256660: Disable DTLS 1.0 DTLS 1.0がデフォルトで無効化。DTLS 1.2を使いましょう (20) JDK-8279164: Disable TLS_ECDH_* cipher suites ECDH暗号スイートがデフォルトで無効化 82

Slide 83

Slide 83 text

Head toward Java 20 and Java 21 [End of slide] KUBOTA Yuji LINE Corporation JJUG CCC 2023/06/04 83

Slide 84

Slide 84 text

以下はメモ 84

Slide 85

Slide 85 text

Java 20 JEP 429: Scoped Values (Incubator) JEP 432: Record Patterns (Second Preview) JEP 433: Pattern Matching for switch (Fourth Preview) JEP 434: Foreign Function & Memory API (Second Preview) JEP 436: Virtual Threads (Second Preview) JEP 437: Structured Concurrency (Second Incubator) JEP 438: Vector API (Fifth Incubator) 85

Slide 86

Slide 86 text

Java 21 JEP 404: Generational Shenandoah (Experimental) JEP 430: String Templates (Preview) JEP 431: Sequenced Collections JEP 439: Generational ZGC JEP 440: Record Patterns JEP 441: Pattern Matching for switch JEP 442: Foreign Function & Memory API (Third Preview) JEP 443: Unnamed Patterns and Variables (Preview) JEP 444: Virtual Threads JEP 445: Unnamed Classes and Instance Main Methods (Preview) JEP 448: Vector API (Sixth Incubator) JEP 449: Deprecate the Windows 32-bit x86 Port for Removal 86

Slide 87

Slide 87 text

Java 21 (未確定 / PROPOSED to Target) JEP 446: Scoped Values (Preview) JEP 451: Prepare to Disallow the Dynamic Loading of Agents JEP 452: Key Encapsulation Mechanism API JEP 453: Structured Concurrency (Preview) 87

Slide 88

Slide 88 text

JDK-8284289: JEP 435: Asynchronous Stack Trace VM API AsyncGetCallTrace を利用した async-profiler のようなエージェントが増えている が、Javaフレームのメソッドとバイトコードのインデックスのみが取れ、1)インライン 化されているかどうか 2)コンパイルレベル(C1 or C2) 3) C/C++フレーム情報が取れな い。 AsyncGetStackTrace というJava及びネイティブフレームを非同期に取得できる APIを提供しようというJEP Container-aware heap sizing for OpenJDK: G1でメモリアンコミット(uncommit)をより 積極的に行う改善など(JDK-8238687) 88

Slide 89

Slide 89 text

{ "threadDump": { "processId": "16460", "time": "2023-06-03T12:41:45.238519600Z", "runtimeVersion": "21-ea+24-2086", "threadContainers": [ { "container": "", "parent": null, "owner": null, "threads": [ { "tid": "1", "name": "main", "stack": [ "java.base\/java.lang.Object.wait0(Native Method)", "java.base\/java.lang.Object.wait(Object.java:366)", "java.base\/java.lang.Object.wait(Object.java:339)", "jdk.jshell\/jdk.jshell.execution.impl.PipeInputStream.read(PipeInputStream.java:53)", "java.base\/java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2893)", "java.base\/java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(ObjectInputStream.java:3107)", "java.base\/java.io.ObjectInputStream$BlockDataInputStream.refill(ObjectInputStream.java:3177)", "java.base\/java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:3336)", "java.base\/java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:3258)", "java.base\/java.io.DataInputStream.readFully(DataInputStream.java:208)", "java.base\/java.io.DataInputStream.readInt(DataInputStream.java:385)", "java.base\/java.io.ObjectInputStream$BlockDataInputStream.readInt(ObjectInputStream.java:3454)", "java.base\/java.io.ObjectInputStream.readInt(ObjectInputStream.java:1160)", "jdk.jshell\/jdk.jshell.execution.ExecutionControlForwarder.processCommand(ExecutionControlForwarder.java:126)", "jdk.jshell\/jdk.jshell.execution.ExecutionControlForwarder.commandLoop(ExecutionControlForwarder.java:266)", "jdk.jshell\/jdk.jshell.execution.Util.forwardExecutionControl(Util.java:78)", "jdk.jshell\/jdk.jshell.execution.Util.forwardExecutionControlAndIO(Util.java:148)", "jdk.jshell\/jdk.jshell.execution.RemoteExecutionControl.main(RemoteExecutionControl.java:74)" ] }, { "tid": "8", "name": "Reference Handler", "stack": [ "java.base\/java.lang.ref.Reference.waitForReferencePendingList(Native Method)", "java.base\/java.lang.ref.Reference.processPendingReferences(Reference.java:246)", "java.base\/java.lang.ref.Reference$ReferenceHandler.run(Reference.java:208)" ] }, { "tid": "9", "name": "Finalizer", "stack": [ "java.base\/java.lang.Object.wait0(Native Method)", "java.base\/java.lang.Object.wait(Object.java:366)", "java.base\/java.lang.Object.wait(Object.java:339)", "java.base\/java.lang.ref.NativeReferenceQueue.await(NativeReferenceQueue.java:48)", "java.base\/java.lang.ref.ReferenceQueue.remove0(ReferenceQueue.java:158)", "java.base\/java.lang.ref.NativeReferenceQueue.remove(NativeReferenceQueue.java:89)", "java.base\/java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:173)" ] }, { "tid": "10", "name": "Signal Dispatcher", "stack": [ ] }, { "tid": "11", "name": "Attach Listener", "stack": [ "java.base\/java.lang.Thread.getStackTrace(Thread.java:2450)", "java.base\/jdk.internal.vm.ThreadDumper.dumpThreadToJson(ThreadDumper.java:262)", "java.base\/jdk.internal.vm.ThreadDumper.dumpThreadsToJson(ThreadDumper.java:237)", "java.base\/jdk.internal.vm.ThreadDumper.dumpThreadsToJson(ThreadDumper.java:201)", "java.base\/jdk.internal.vm.ThreadDumper.dumpThreadsToFile(ThreadDumper.java:115)", "java.base\/jdk.internal.vm.ThreadDumper.dumpThreadsToJson(ThreadDumper.java:84)" ] }, { "tid": "21", "name": "Notification Thread", "stack": [ ] }, { "tid": "23", "name": "Common-Cleaner", "stack": [ "java.base\/jdk.internal.misc.Unsafe.park(Native Method)", "java.base\/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:269)", "java.base\/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1847)", "java.base\/java.lang.ref.ReferenceQueue.await(ReferenceQueue.java:71)", "java.base\/java.lang.ref.ReferenceQueue.remove0(ReferenceQueue.java:143)", "java.base\/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:218)", "java.base\/jdk.internal.ref.CleanerImpl.run(CleanerImpl.java:140)", "java.base\/java.lang.Thread.run(Thread.java:1583)", "java.base\/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:186)" ] }, { "tid": "24", "name": "output reader", "stack": [ "java.base\/sun.nio.ch.SocketDispatcher.read0(Native Method)", "java.base\/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:46)", "java.base\/sun.nio.ch.NioSocketImpl.tryRead(NioSocketImpl.java:256)", "java.base\/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:307)", "java.base\/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:346)", "java.base\/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:796)", "java.base\/java.net.Socket$SocketInputStream.read(Socket.java:1099)", "java.base\/java.net.Socket$SocketInputStream.read(Socket.java:1093)", "java.base\/java.io.FilterInputStream.read(FilterInputStream.java:71)", "jdk.jshell\/jdk.jshell.execution.DemultiplexInput.run(DemultiplexInput.java:60)" ] }, { "tid": "25", "name": "Read-Poller", "stack": [ "java.base\/sun.nio.ch.WEPoll.wait(Native Method)", "java.base\/sun.nio.ch.WEPollPoller.poll(WEPollPoller.java:65)", "java.base\/sun.nio.ch.Poller.poll(Poller.java:363)", "java.base\/sun.nio.ch.Poller.pollLoop(Poller.java:270)", "java.base\/java.lang.Thread.run(Thread.java:1583)", "java.base\/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:186)" ] }, { "tid": "26", "name": "Read-Updater", "stack": [ "java.base\/jdk.internal.misc.Unsafe.park(Native Method)", "java.base\/java.util.concurrent.locks.LockSupport.park(LockSupport.java:371)", "java.base\/java.util.concurrent.LinkedTransferQueue$Node.block(LinkedTransferQueue.java:470)", "java.base\/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3780)", "java.base\/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3725)", "java.base\/java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:669)", "java.base\/java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:616)", "java.base\/java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1286)", "java.base\/sun.nio.ch.Poller.updateLoop(Poller.java:286)", "java.base\/java.lang.Thread.run(Thread.java:1583)", "java.base\/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:186)" ] }, { "tid": "27", "name": "Write-Poller", "stack": [ "java.base\/sun.nio.ch.WEPoll.wait(Native Method)", "java.base\/sun.nio.ch.WEPollPoller.poll(WEPollPoller.java:65)", "java.base\/sun.nio.ch.Poller.poll(Poller.java:363)", "java.base\/sun.nio.ch.Poller.pollLoop(Poller.java:270)", "java.base\/java.lang.Thread.run(Thread.java:1583)", "java.base\/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:186)" ] }, { "tid": "28", "name": "Write-Updater", "stack": [ "java.base\/jdk.internal.misc.Unsafe.park(Native Method)", "java.base\/java.util.concurrent.locks.LockSupport.park(LockSupport.java:371)", "java.base\/java.util.concurrent.LinkedTransferQueue$Node.block(LinkedTransferQueue.java:470)", "java.base\/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3780)", "java.base\/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3725)", "java.base\/java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:669)", "java.base\/java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:616)", "java.base\/java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1286)", "java.base\/sun.nio.ch.Poller.updateLoop(Poller.java:286)", "java.base\/java.lang.Thread.run(Thread.java:1583)", "java.base\/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:186)" ] } ], "threadCount": "12" }, { "container": "ForkJoinPool.commonPool\/jdk.internal.vm.SharedThreadContainer@88950e6", "parent": "", "owner": null, "threads": [ ], "threadCount": "0" }, { "container": "java.util.concurrent.ThreadPoolExecutor@485dae5d\/jdk.internal.vm.SharedThreadContainer@75907f2", "parent": "", "owner": null, "threads": [ ], "threadCount": "0" } ] } } 89

Slide 90

Slide 90 text

90