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

Virtual Threads - 導入の背景と、効果的な使い方 -

Virtual Threads - 導入の背景と、効果的な使い方 -

2023.06.04 JJUG CCC セッション資料

Yuichi.Sakuraba

June 04, 2023
Tweet

More Decks by Yuichi.Sakuraba

Other Decks in Technology

Transcript

  1. Virtual Threads
    -導入の背景と効果的な使い方 -
    櫻庭 祐一
    Java in the Box

    View Slide

  2. 3 分でわかる Virtual Threads
    JVM が管理する軽量スレッド
    Fiber
    他言語でいうところの
    スループット向上が目的
    I/Oを多く含むシステムで効果的
    応答時間はちょっとだけ悪化
    従来のスレッドと使い方は同じ
    使用上の注意点はある

    View Slide

  3. 導入の背景
    Agenda
    歴史的経緯とともに
    動作原理
    なぜスループットが向上するのか
    効果的な使い方
    ユースケースをもとに

    View Slide

  4. 導入の背景
    歴史的経緯とともに

    View Slide

  5. 2004
    2011
    2014
    2023
    1995
    Java 5
    Java 7
    Java 8
    Java 21
    Java 1.0

    View Slide

  6. 2004
    2011
    2014
    2023
    1995
    Java 5
    Java 7
    Java 8
    Java 21
    Java 1.0
    Single Core の時代
    Thread = OSスレッドのラッパー
    Threadの切替 : スレッドのコンテキストスイッチ
    OS
    Threadオブジェクト生成: 重い & メモリ消費大

    View Slide

  7. OS Thread
    Java Thread
    JVM Stack
    new Thread(new Runnable() {
    public void run() {
    foo();
    }
    }).start();
    run()
    Frame
    void foo() {
    bar();
    }
    foo() void bar() {
    ...
    }
    bar()

    View Slide

  8. OS Thread
    Java Thread
    JVM Stack
    new Thread(new Runnable() {
    public void run() {
    foo();
    }
    }).start();
    run()
    Frame
    void foo() {
    bar();
    }
    foo() void bar() {
    ...
    }
    bar()
    run()
    foo()
    bar()
    Operand Stack
    Local Var.

    View Slide

  9. OS Thread
    Java Thread
    JVM Stack
    run()
    foo()
    bar()
    Operand Stack
    Local Var.
    のコンテキストスイッチ
    Thread
    のスレッドの状態
    OS
    オブジェクトの状態
    Thread
    JVM Stack
    +
    +
    の退避・復帰

    View Slide

  10. 2004
    2011
    2014
    2023
    1995
    Java 5
    Java 7
    Java 8
    Java 21
    Java 1.0
    Single Core の時代
    Thread = OSスレッドのラッパー
    Threadの切替 : スレッドのコンテキストスイッチ
    OS
    Threadオブジェクト生成: 重い & メモリ消費大
    重い & メモリ消費大
    コンテキストスイッチをなるべく発生させない
    スレッドスケジューリング

    View Slide

  11. 2011
    2014
    2023
    Java 7
    Java 8
    Java 21
    Java 1.0
    1995
    2004 Java 5
    Multi Core 黎明期
    Concurrency Utilities
    スレッドとタスクの分離
    スレッドプール導入
    Executors.newFixedThreadPool 応答時間重視
    Executors.newCachedThreadPool スループット重視
    リクエスト増大 スループット頭打ち
    Thread per Request/Task

    View Slide

  12. 2011
    2014
    2023
    Java 7
    Java 8
    Java 21
    Java 1.0
    1995
    2004 Java 5
    Multi Core 黎明期
    public class ThreadPoolExecutor
    extends AbstractExecutorService {
    ...
    private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable {
    Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
    }
    ...
    Apache Tomcat

    View Slide

  13. 2014
    2023
    Java 8
    Java 21
    Java 1.0
    1995
    2004 Java 5
    2011 Java 7
    Big Dataの時代
    Fork/Join Framework
    分割統治法 タスクを細粒度に分割して処理
    Work-Stealing タスクスケジューラー
    スレッドごとにタスクキュー
    キューが空の時は他のスレッドからタスクを盗む
    効率的なタスクスケジューリング

    View Slide

  14. 業務タスクの特徴
    Comp. I/O C I/O I/O
    C C
    通信、
    DBアクセスなど I/O処理が多い
    I/O処理は計算処理に対して多大な時間を要する
    I/Oの待ち時間が長い
    その中でも
    I/O待ちの間 CPUが遊んでしまう
    I/O待ちの間に他の処理を行いたい

    View Slide

  15. 2023 Java 21
    Java 1.0
    1995
    2004 Java 5
    2011 Java 7
    2014 Java 8
    Project Lambda
    ラムダ式の導入 処理を関数として記述
    CompletableFuture
    Reactive Programming
    非同期処理を関数で記述
    CompletableFuture
    Reactive Programming
    ex. Spring WebFlux
    Oracle Helidon SE
    処理を非同期実行することで
    スループット向上
    I/O
    とはいうものの
    従来の逐次的な記述と考え方が異なる ...
    例外処理が ...
    デバッグが ...

    View Slide

  16. Java 1.0
    1995
    2004 Java 5
    2011 Java 7
    2014 Java 8
    2023 Java 21
    従来の逐次的な記述で
    例外処理をあつかいやすく
    デバッグもやりやすいままで
    スループットを向上させたい
    Virtual Threads

    View Slide

  17. 動作原理
    なぜスループットが向上するのか

    View Slide

  18. Virtual Threads
    Platform Threadとタスクの仲介
    Platform Thread
    タスクからは と区別がつかない
    Platform Thread にマウントして実行
    Carrier Thread
    マウントしたスレッドを と呼ぶ
    積極的なコンテキストスイッチ
    限定継続を導入してコンテキストスイッチの高速化
    Work-Stealingによるスレッドスケジューリング
    一貫性のあるスタックトレース
    Carrier Threadが変わってもスタックトレースが切れない

    View Slide

  19. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    Instantiation

    View Slide

  20. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    Mount

    View Slide

  21. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    I/O Wait

    View Slide

  22. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    Unmount

    View Slide

  23. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task I/O Interrupt

    View Slide

  24. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    Mount

    View Slide

  25. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    I/O待ち時間の活用による大幅なスループット向上
    頻繁なコンテキストスイッチによる応答時間の悪化

    View Slide

  26. Platform Thread Platform Thread
    ......
    Virtual Thread
    Task
    public int read(ByteBuffer buf) throws IOException {
    ...
    readLock.lock();
    try {
    ...
    configureSocketNonBlockingIfVirtualThread();
    n = IOUtil.read(fd, buf, -1, nd);
    if (blocking) {
    while (IOStatus.okayToRetry(n) && isOpen()) {
    park(Net.POLLIN);
    n = IOUtil.read(fd, buf, -1, nd);
    }
    }
    ...
    sun.nio.ch.SocketChannelImpl

    View Slide

  27. void park() {
    ...
    boolean yielded = false;
    setState(PARKING);
    try {
    yielded = yieldContinuation();
    } finally {
    ...
    }
    ...
    }
    java.lang.VirtualThread
    private boolean yieldContinuation() {
    ...
    unmount();
    try {
    return Continuation.yield(VTHREAD_SCOPE);
    } finally {
    mount();
    ...
    }
    }
    限定継続

    View Slide

  28. 効果的な使い方
    ユースケースをもとに

    View Slide

  29. Virtual Threadsの使い方
    ExecutorServiceを介して利用する
    Executors.newVirtualThreadPerTaskExecutor()
    Executors.newThreadPerTaskExecutor(
    Thread.ofVirtual().factory())
    or
    Virtual Threadの直接生成も可能だが、基本はやらない
    ExecutorServiceを定義する場合だけ
    独自の
    ExecutorServiceはJava 19からAutoClosable

    View Slide

  30. Virtual Threadsの使い方
    try (var pool
    = Executors.newVirtualThreadPerTaskExecutor()) {
    Runnable task = ...;
    pool.submit(task);
    }

    View Slide

  31. VT 使いたい
    Y
    FWを使ってる ?
    VT使う必要なし
    WebFluxなどのリアクティブ系
    or CompletableFutureゴリゴリ書ける
    Spring Boot, Jakarta EE など
    FWの対応待ち
    その他 使ってない
    or

    View Slide

  32. VT使う必要なし
    or CompletableFutureゴリゴリ書ける
    Spring Boot, Jakarta EE など
    FWの対応待ち
    その他 使ってない
    or
    ボトルネックは?
    データ量 / 計算量 ParallelStream
    Fork/Join FW
    Vector API
    File
    Memory Map
    DB
    通信 /
    VirtualThread

    View Slide

  33. スレッドの注意点 Virtual Threads
    特に
    synchronizedをなるべく使わないようにする
    1.
    synchronized = モニタロック
    リソースへのアクセスを 1 つのスレッドだけに限定
    他のスレッドをブロックする
    ボトルネックになりやすい
    Virtual Threadでは Carrier Threadをブロックしてしまう

    View Slide

  34. スレッドの注意点 Virtual Threads
    特に
    synchronized を使わないようにするには
    イミュータブルクラスの活用
    record 型の利用
    状態が変化しなければ複数スレッドからもアクセス可
    処理結果の受け渡しがある場合 Callableを使う
    どうしてもロックが必要であれば
    synchronizedではなくReentrantLock クラスを使う
    java.util.concurrent.locksにロッククラスあり
    他にも

    View Slide

  35. スレッドの注意点 Virtual Threads
    特に
    ThreadLocal を使わない
    2.
    ThreadLocal はミュータブル & ライフタイムが不明確
    Virtual Threads ThreadLocalをサポートしているが

    スケールしないためボトルネック化
    ScopedValueで代用する
    Java 21 Preview JEP
    では
    ただし
    FWが ThreadLocal を使っている場合
    対応してくれるまで待ちましょう

    View Slide

  36. スレッドの注意点 Virtual Threads
    特に
    スレッドを使いまわさない
    3.
    Virtual Threadsは使い捨て
    ExecutorService
    スレッドのプールは にまかせる
    タスクを記述することに集中しよう
    クラスの
    4. Thread APIをもう 1 度チェック
    @Deprecated(forRemoval=true)なメソッド
    stop, suspend, resumeなど

    View Slide

  37. Conclusion
    Virtual Threadsによりスループットが向上
    I/Oの待ち時間を有効活用
    Virtual Threadsは従来のスレッドを同じ使い方
    使用時の注意点を把握する
    FWで Virtual Threads がサポートされるのを楽しみに待つ

    View Slide

  38. Virtual Threads
    -導入の背景と効果的な使い方 -
    櫻庭 祐一
    Java in the Box

    View Slide