Java 19虚拟线程实战与性能分析

Java 19推出了新特性“虚拟线程”,类似于Go语言中的协程。它是传统线程的不同之处在于,它是一种用户模式(user-mode)的线程。

虚拟线程是由 JDK 而非操作系统提供的线程的轻量级实现:

虚拟线程是没有绑定到特定操作系统线程的线程。

平台线程是以传统方式实现的线程,作为围绕操作系统线程的简单包装。

下面让我们实际开发一个多线程的程序,分别使用传统线程和虚拟线程,再来对比一下它们运行期间的性能表现。

该程序会创建10万个线程,每个线程并发运行(先睡眠一秒,再打印一个数字),运行完之后打印运行时间

传统线程程序

public class OSThreadMain {
    public static void main(String[] args) throws InterruptedException, IOException {
        TimeUnit.SECONDS.sleep(60);
        AtomicInteger count = new AtomicInteger();
        long start = System.currentTimeMillis();
        try (var executor = Executors.newCachedThreadPool()) {
            IntStream.range(0, 100000).forEach(i -> {
                executor.submit(() -> {
                    System.out.println("参数" + (count.getAndIncrement()));
                    Thread.sleep(Duration.ofSeconds(1));
                    return i;
                });
            });
        }
        System.out.println("耗时" + (System.currentTimeMillis() - start));
        System.in.read();
    }
}

该代码中使用了线程池。

运行结果

Java 19虚拟线程实战与性能分析_第1张图片

可见整体运行时间达到了38秒多。

同时我用JConsole连接了程序,得到的监控图像

Java 19虚拟线程实战与性能分析_第2张图片

可以看出,整个程序运行过程中,比较突出的资源使用是线程数和CPU占用率,线程数达到了将近4000个线程,并持续了程序运行的大部分有效时间(前面为了能让JConsole能先连接上程序再进行监测,程序首先睡了60秒)。同时CPU的占用率也在程序有效运行时间内保持在30%到40%之间。

下面再看虚拟线程代码

public class VirtualThreadMain {
    public static void main(String[] args) throws IOException, InterruptedException {
        TimeUnit.SECONDS.sleep(60);
        AtomicInteger count = new AtomicInteger();
        long start = System.currentTimeMillis();
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            IntStream.range(0, 100000).forEach(i -> {
                executor.submit(() -> {
                    System.out.println("参数" + (count.getAndIncrement()));
                    Thread.sleep(Duration.ofSeconds(1));
                    return i;
                });
            });
        }
        System.out.println("耗时" + (System.currentTimeMillis() - start));
        System.in.read();
    }
}

除了使用了newVirtualThreadPerTaskExecutor方法代替newCachedThreadPool方法之外,代码完全相同。

运行结果

Java 19虚拟线程实战与性能分析_第3张图片

程序运行只花了4323毫秒,仅为传统线程的九分之一。再看JConsole监控结果

 Java 19虚拟线程实战与性能分析_第4张图片

可见线程数仅为21个左右,而CPU占用率也仅是在一瞬间触达33%左右即迅速回落。可见在线程数和CPU占用率上,虚拟线程大大优于传统线程。

不过值得一提的是,从上两图可看出,传统线程内存占用仅150MB左右,而虚拟线程则为300MB左右,有两倍的差异。这是因为虚拟线程是JDK在用户模式实现,所以需要更复杂的数据结构去实现,而传统线程,则依赖于操作系统,所以JVM的内存占用就少了。 

你可能感兴趣的:(多线程,虚拟线程,java,虚拟线程,多线程)