个人浅学jdk21的virtual thread

What is a Platform Thread?

A platform thread is implemented as a thin wrapper around an operating system (OS) thread. A platform thread runs Java code on its underlying OS thread, and the platform thread captures its OS thread for the platform thread's entire lifetime. Consequently, the number of available platform threads is limited to the number of OS threads.

Platform threads typically have a large thread stack and other resources that are maintained by the operating system. They are suitable for running all types of tasks but may be a limited resource.

什么是平台线程

平台线程是对操作系统线程的一个薄封装。一个平台线程将Java代码运行在它底层的操作线程上,它在其整个生命周期里都捕获着操作系统线程,因此,可用的平台线程数被限制为操作系统线程数

平台线程通常拥有一个巨大的线程栈,以及其他被操纵系统所维护的资源。它们适合执行所有类型的任务但拥有有限的资源

What is a Virtual Thread?

Like a platform thread, a virtual thread is also an instance of java.lang.Thread. However, a virtual thread isn't tied to a specific OS thread. A virtual thread still runs code on an OS thread. However, when code running in a virtual thread calls a blocking I/O operation, the Java runtime suspends the virtual thread until it can be resumed. The OS thread associated with the suspended virtual thread is now free to perform operations for other virtual threads.

Virtual threads are implemented in a similar way to virtual memory. To simulate a lot of memory, an operating system maps a large virtual address space to a limited amount of RAM. Similarly, to simulate a lot of threads, the Java runtime maps a large number of virtual threads to a small number of OS threads.

Unlike platform threads, virtual threads typically have a shallow call stack, performing as few as a single HTTP client call or a single JDBC query. Although virtual threads support thread-local variables and inheritable thread-local variables, you should carefully consider using them because a single JVM might support millions of virtual threads.

Virtual threads are suitable for running tasks that spend most of the time blocked, often waiting for I/O operations to complete. However, they aren't intended for long-running CPU-intensive operations.

什么是虚拟线程

就像一个平台线程那样,一个虚拟线程也是一个java.lang.Thread的实例,然而,一个虚拟线程并不与某个操作系统线程所绑定。一个虚拟线程仍然是在操作系统线程上运行代码,然而,当运行在虚拟线程中的代码调用了一个阻塞的IO操作时,Java运行时会将虚拟线程暂时挂起直到它可以被恢复运行,此时与被挂起的虚拟线程所关联的操作系统线程便有空去执行其他虚拟线程。

虚拟线程的实现方式有点像虚拟内存。为了模拟大量的内存,操作系统将会映射大量的虚拟地址空间到有限数量的RAM(不太看得懂,没有相关知识)。类似的,为了模拟大量的线程,Java运行时会将大量的虚拟线程映射到少数的操作系统线程上

与平台线程不同,虚拟线程有比较浅的调用栈,执行像单个http请求或者单个JDBC查询操作一样少的操作。尽管虚拟线程支持thread-local变量和可继承的thread-local变量,但是当你要使用它们的时候应该谨慎考虑,因为一个jvm也许会支持上百万个虚拟线程

虚拟线程适合执行那种大部分时间都在阻塞的,在等待IO操作完成的任务。然而,它们并不适用于长久运行的cpu密集型操作。

Why Use Virtual Threads?

Use virtual threads in high-throughput concurrent applications, especially those that consist of a great number of concurrent tasks that spend much of their time waiting. Server applications are examples of high-throughput applications because they typically handle many client requests that perform blocking I/O operations such as fetching resources.

Virtual threads are not faster threads; they do not run code any faster than platform threads. They exist to provide scale (higher throughput), not speed (lower latency).

为何使用虚拟线程

虚拟线程适合被用在高吞吐量的并发程序中,特别是那些拥有大量并发的,且通常需要阻塞等待的任务的情况下。服务器程序就是这样一个例子,吞吐量高,因为它们通常需要处理许多客户端请求,且需要执行阻塞的IO任务例如获取资源(例如查数据库?)。

虚拟线程并不比普通线程快,它们并会不比平台线程更快地执行代码,它们存在的意义是提高吞吐量,而不是速度

Creating and Running a Virtual Thread

The `Thread` and `Thread.Builder` APIs provide ways to create both platform and virtual threads. The `java.util.concurrent.Executors` class also defines methods to create an ExecutorService that starts a new virtual thread for each task.

创建并执行虚拟线程

`Thread`以及`Thread.Builder`API都提供了创建平台线程和虚拟线程的方式,`java.util.concurrent.Executors`也提供了创建能为每个提交的任务开始一个虚拟线程的`ExecutorService`的方法。

使用Thread和builder来创建虚拟线程

直接创建并执行一个虚拟线程

public static void main(String[] args) throws InterruptedException {
  var thread = Thread.ofVirtual().start(() -> System.out.println("start"));
  thread.join();
}

使用Builder接口

public static void main(String[] args) throws InterruptedException {
  var builder = Thread.ofVirtual().name("test");
  var thread = builder.start(() -> System.out.println(Thread.currentThread().getName() + " running"));
  thread.join();

  /*
    test running
   */
}

通过Builder可创建并执行多个线程

public static void main(String[] args) throws InterruptedException {
  // name(prefix: String, start: int) 第二个参数是计数器,每创建一个线程加一,线程名便是"thread-1", "thread-2"
  var builder = Thread.ofVirtual().name("thread-", 1);
  var thread1 = builder.start(() -> System.out.println(Thread.currentThread().getName() + " running"));
  var thread2 = builder.start(() -> System.out.println(Thread.currentThread().getName() + " running"));
  thread1.join();
  thread2.join();
  /* 
    thread-0 running
    thread-1 running
   */
}

虚拟线程 vs 平台线程

测试方法

从这篇文获得的启示: https://juejin.cn/post/7280746515526058038

/**
 * 用给定的ExecutorService执行任务,每个任务内阻塞1s
 * @param service ExecutorService
 * @param countDownLatch CountDownLatch
 */
static void runTasks(ExecutorService service, CountDownLatch countDownLatch, AtomicInteger counter) {
  for (int i = 0; i < 500; i++) {
    service.submit(() -> {
      try {
        // simulate blocking
        Thread.sleep(1000L);
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        counter.getAndIncrement();
        countDownLatch.countDown();
      }
    });
  }
}

main方法(普通线程池,500个任务,100个线程,遇到阻塞时底层操作系统线程仍然被占有,一百个任务并行执行完之后,下一批一百个任务才能继续被并行执行,由于是并行执行,所以一批任务总共只需等待1s,分五批执行,最终耗时5s)

public static void main(String[] args) {
  var countdownLatch = new CountDownLatch(500);
  // newFixedThreadPool
  try (var service = Executors.newFixedThreadPool(100)) {
    long start = System.currentTimeMillis();
    AtomicInteger counter = new AtomicInteger();
    runTasks(service, countdownLatch, counter);
    countdownLatch.await();
    System.out.println("result: " + counter.get());
    System.out.println("用时: " + (System.currentTimeMillis() - start));
  } catch (Exception e) {
    e.printStackTrace();
  }
}

输出结果

result: 500
用时: 5059

main方法(改成虚拟线程,遇到阻塞时虚拟线程被挂起,底层的操作系统线程可以去执行其他的虚拟线程的操作,保证所有任务能够同时并行执行,只需耗时1s)

public static void main(String[] args) {
  var countdownLatch = new CountDownLatch(500);
  // newVirtualThreadPerTaskExecutor
  try (var service = Executors.newVirtualThreadPerTaskExecutor()) {
    var counter = new AtomicInteger();
    long start = System.currentTimeMillis();
    runTasks(service, countdownLatch, counter);
    countdownLatch.await();
    System.out.println("result: " + counter.get());
    System.out.println("用时: " + (System.currentTimeMillis() - start));
  } catch (Exception e) {
    e.printStackTrace();
  }
}

输出结果

result: 500
用时: 1027
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值