Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Head toward Java 20 and Java 21

Head toward Java 20 and Java 21

まいどおなじみ最新のJava技術についてお届けします!

本セッションでは2023年3月にリリースされた(本Proposal投稿時点では「予定」)Java 20、そして予定通りであれば2023年9月にリリース予定である、次のLong Term SupportであるJava 21についてどのような機能や変更点が入ったのか・入る予定なのかを紹介し、「このセッションさえ聞けば今の最新状況が分かる!」を目指します。

OpenJDKコミュニティではLTSかどうかに関わらず一定品質以上を保ちつつ提供することをポリシーとしているため、LTSであるJava 21でも従来通り試験的な(IncubatorやPreview)機能が導入される予定です。

最近のJavaでは大きなプロジェクトが長く続いていることもあり、JEP(Java Enhance Proposal)レベルの変更はやや控えめですが、本セッションでは発表当日までのJava 21の開発状況を含めて、未だ止まることなく進化を続けるJavaを余すどころなくお伝えしていきます!

Yuji Kubota
LINE,Senior software engineer
OpenJDK Author, icedtea committer

※この資料は以下イベントで発表した内容です。
https://sessionize.com/api/v2/y7inyq6y/view/GridSmart

LINE Developers
PRO

June 04, 2023
Tweet

More Decks by LINE Developers

Other Decks in Technology

Transcript

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

    View Slide

  2. 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

    View Slide

  3. 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

    View Slide

  4. アップデートと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

    View Slide

  5. 今日の流れ
    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

    View Slide

  6. 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

    View Slide

  7. 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

    View Slide

  8. 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

    View Slide

  9. 使用方法(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

    View Slide

  10. 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

    View Slide

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

    View Slide

  12. 変更点
    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

    View Slide

  13. 使用方法(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

    View Slide

  14. 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

    View Slide

  15. 正常処理と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

    View Slide

  16. 条件処理
    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

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. 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

    View Slide

  20. 使用方法(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

    View Slide

  21. 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

    View Slide

  22. 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

    View Slide

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

    View Slide

  24. 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

    View Slide

  25. 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

    View Slide

  26. 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

    View Slide

  27. 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

    View Slide

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

    View Slide

  29. 使用方法(予定)(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

    View Slide

  30. 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

    View Slide

  31. // 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

    View Slide

  32. 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

    View Slide

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

    View Slide

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

    View Slide

  35. 使用方法(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

    View Slide

  36. 注意事項 (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

    View Slide

  37. 注意事項 (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

    View Slide

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

    View Slide

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

    View Slide

  40. 変更点
    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

    View Slide

  41. 使用方法(予定)(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

    View Slide

  42. 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

    View Slide

  43. 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

    View Slide

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

    View Slide

  45. 変更点
    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

    View Slide

  46. 使用方法(予定)(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

    View Slide

  47. 実行中のスレッドいずれかが返ってきたら他をすべてシャットダウン
    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

    View Slide

  48. 実行中のスレッドいずれかが例外を出したらすべてシャットダウン
    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

    View Slide

  49. スレッドダンプによる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

    View Slide

  50. 50

    View Slide

  51. 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

    View Slide

  52. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  56. 使用方法(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

    View Slide

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

    View Slide

  58. 変更点
    かれこれ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

    View Slide

  59. 使用方法(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

    View Slide

  60. 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

    View Slide

  61. 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

    View Slide

  62. 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

    View Slide

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

    View Slide

  64. 逆順で反復処理する際の書き方
    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

    View Slide

  65. 65

    View Slide

  66. 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

    View Slide

  67. 67

    View Slide

  68. SequencedSet
    重複を含まない SequencedCollection
    の Set
    SortedSet
    のように相対比較で要素を配置するコレクションは、 addFirst(E)

    addLast(E)
    のような明示的な配置操作ができないため、
    UnsupportedOperationException
    をスロー
    interface SequencedSet extends Set, SequencedCollection {
    SequencedSet reversed(); // covariant override (+ Set)
    }
    68

    View Slide

  69. 69

    View Slide

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

    View Slide

  71. 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

    View Slide

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

    View Slide

  73. 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

    View Slide

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

    Instrumentation APIが呼び出された時にスタックトレースを出せる (JVM TIは非対応)
    74

    View Slide

  75. 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

    View Slide

  76. 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

    View Slide

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

    View Slide

  78. 共通鍵暗号で鍵カプセル化
    // 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

    View Slide

  79. 鍵非カプセル化(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

    View Slide

  80. 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

    View Slide

  81. 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

    View Slide

  82. 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

    View Slide

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

    View Slide

  84. 以下はメモ
    84

    View Slide

  85. 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

    View Slide

  86. 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

    View Slide

  87. 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

    View Slide

  88. 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

    View Slide

  89. {
    "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

    View Slide

  90. 90

    View Slide