Javaでプラットフォームスレッドだと終了を待ってくれるのに仮想スレッドだと途中でプロセスが終わる

Javaで、プラットフォームスレッドだとmainメソッドが終わってもスレッド終了を待ってくれるのに、仮想スレッドだとmainスレッドが終わると仮想スレッドの処理が途中でもプロセスが終わるの何でだろうな、と思った話。

こういうコードを動かします。

void main() {
    Thread.ofPlatform().start(() -> {
        IO.println("start");
        sleep(2);
        IO.println("end");
    });
    IO.println("hello");
    IO.println("fin");
}
void sleep(int sec) {
    try {
        Thread.sleep(Duration.ofSeconds(sec));
    } catch (InterruptedException ex) {
    }
}

そうすると、スレッドがendまで出力するのを待ってからプロセスが終わります。

hello
fin
start
end

これを仮想スレッドにしてみます。

void main() {
    Thread.ofVirtual().start(() -> {
        IO.println("start");
        sleep(2);
        IO.println("end");
    });
    IO.println("hello");
    IO.println("fin");
}

endにくる前にプロセスが終わってしまいました。

hello
fin
start

どういう仕様に基づくんだろうな、と思ってたら、仮想スレッドは常にデーモンスレッドだということを教えてもらいました。

Virtual threads are always daemon threads. The Thread.setDaemon(boolean) method cannot change a virtual thread to be a non-daemon thread.

JEP 444: Virtual Threads

デーモンではないスレッドがひとつでも動いてるときはプロセスは終わらず、動いてるスレッドがデーモンスレッドだけになるとプロセスは終わります。

ということで、プラットフォームスレッドでも、daemon()を加えてデーモンスレッドにすると仮想スレッドの場合と同様に処理の途中でプロセスが終わるようになりました。

void main() {
    Thread.ofPlatform().daemon().start(() -> {
        IO.println("start");
        sleep(2);
        IO.println("end");
    });
    IO.println("hello");
    IO.println("fin");
}
hello
fin
start

ところで、例外を気にしなくていいIO.sleepが欲しい。