searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Java21新特性——虚拟线程

2023-10-27 07:01:30
109
0

一、一句话描述虚拟线程

       虚拟线程是一个新的轻量级 java.lang.Thread 变体,不由操作系统管理或调度,由 JVM 负责调度。JVM通过复用、管理、调用系统平台线程达到轻量线程的目的。

二、使用虚拟线程池例子

 private static void testVirtualThread() {
        var a = new AtomicInteger(0);
        // 创建一个固定200个线程的线程池
        try (var vs = Executors.newVirtualThreadPerTaskExecutor()) {
            List<Future<Integer>> futures = new ArrayList<>();
            var begin = System.currentTimeMillis();
            // 向线程池提交1000个sleep 1s的任务
            for (int i = 0; i < 1_000; i++) {
                var future = vs.submit(() -> {
                    Thread.sleep(Duration.ofSeconds(1));
                    return a.addAndGet(1);
                });
                futures.add(future);
            }
            // 获取这1000个任务的结果
            for (var future : futures) {
                var i = future.get();
                if (i % 100 == 0) {
                    System.out.print(i + " ");
                }
            }
            // 打印总耗时
            System.out.println("Exec finished.");
            System.out.printf("Exec time: %dms.%n", System.currentTimeMillis() - begin);
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }

这段代码逻辑很简单,创建一个虚拟线程池,并向虚拟线程池中体检1000个任务,每个任务睡1秒钟并打印最终执行时间。
当把创建虚拟线程池的方法改成传统线程池的代码后,我们可以得到传统方法,具体如下

    private static void testThread() {
        var a = new AtomicInteger(0);
        // 创建一个固定200个线程的线程池
        try (var vs = Executors.newFixedThreadPool(200)) {
            List<Future<Integer>> futures = new ArrayList<>();
            var begin = System.currentTimeMillis();
            // 向线程池提交1000个sleep 1s的任务
            for (int i = 0; i < 1_000; i++) {
                var future = vs.submit(() -> {
                    Thread.sleep(Duration.ofSeconds(1));
                    return a.addAndGet(1);
                });
                futures.add(future);
            }
            // 获取这1000个任务的结果
            for (var future : futures) {
                var i = future.get();
                if (i % 100 == 0) {
                    System.out.print(i + " ");
                }
            }
            // 打印总耗时
            System.out.println("Exec finished.");
            System.out.printf("Exec time: %dms.%n", System.currentTimeMillis() - begin);
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }

运行这两段代码,分别得到两段代码的耗时,耗时如下
虚拟线程耗时:1026ms
平台线程耗时:5094ms
通过结果看出使用虚拟线程池可以提升性能约500%。

三、虚拟线程作用

       区别于虚拟线程,传统的线程对象叫做平台线程(platform thread)。平台线程在底层 OS 线程上运行 Java 代码,并在代码的整个生命周期中占用该 OS 线程,因此平台线程的数量受限于 OS 线程的数量。虚拟线程是 java.lang.Thread 的一个实例,它在底层 OS 线程上运行 Java 代码,但不会在代码的整个生命周期中占用该 OS 线程。也就是说,多个虚拟线程可以在同一个 OS 线程上运行其 Java 代码,可以有效地共享该线程。平台线程独占宝贵的 OS 线程,而虚拟线程则不会,因此虚拟线程的数量可以比 OS 线程的数量多得多,执行阻塞任务的整体吞吐量也就大了很多。虚拟线程虽然可以带来更大的吞吐量,但并不能让单个任务计算得更快。虚拟线程可以发挥的最大作用是,可以让采用单请求单线程(thread-per-request)的方式编写的服务器程序最大化地利用CPU计算资源 。 其原因在于服务器程序有两大特点,一是需要处理较大吞吐量的请求,二是请求处理的过程大多是由IO密集型逻辑组成,这就导致采用平台线程实现的单请求单线程编写方式,可能会有大量的IO阻塞占据了平台线程资源,从而不能充分利用CPU资源,使用虚拟线程带来的服务可用性提升会非常明显。

0条评论
0 / 1000