首页 > 编程语言 >Java SE 19 虚拟线程

Java SE 19 虚拟线程

时间:2022-09-26 20:26:04浏览次数:84  
标签:Task Java Thread 19 虚拟 线程

Java SE 19 虚拟线程

作者:Grey

原文地址:

博客园:Java SE 19 虚拟线程

CSDN:Java SE 19 虚拟线程

说明

虚拟线程(Virtual Threads)是在Project Loom中开发的,并从 Java SE 19 开始作为预览功能引入 JDK。

在线程模型下,一个 Java 线程相当于一个操作系统线程,而这些线程是很消耗资源的,如果启动的线程过多,会给整个系统的稳定性带来风险。

虚拟线程解决了这个问题,从 Java 代码的角度来看,虚拟线程感觉就像普通的线程,但它们不是 1:1 地映射到操作系统线程上。

有一个所谓的载体线程池,一个虚拟线程被临时映射到该池中。一旦虚拟线程遇到阻塞操作,该虚拟线程就会从载体线程中移除,而载体线程可以执行另一个虚拟线程(新的或之前被阻塞的)。

所以阻塞的操作不再阻塞执行的线程。这使得我们可以用一个小的载体线程池来并行处理大量的请求。

示例

场景

启动 1000 个任务,每个任务等待一秒钟(模拟访问外部API),然后返回一个结果(在这个例子中是一个随机数)。

任务类如下

package git.snippets.vt;

import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author <a href="mailto:[email protected]">Grey</a>
 * @date 2022/9/21
 * @since 19
 */
public class Task implements Callable<Integer> {

    private final int number;

    public Task(int number) {
        this.number = number;
    }

    @Override
    public Integer call() {
        System.out.printf("Thread %s - Task %d waiting...%n", Thread.currentThread().getName(), number);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.printf("Thread %s - Task %d canceled.%n", Thread.currentThread().getName(), number);
            return -1;
        }
        System.out.printf("Thread %s - Task %d finished.%n", Thread.currentThread().getName(), number);
        return ThreadLocalRandom.current().nextInt(100);
    }
}

接下来,我们测试使用线程池开启 100 个线程处理 1000 个任务需要多长时间。

package git.snippets.vt;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author <a href="mailto:[email protected]">Grey</a>
 * @date 2022/9/21
 * @since 19
 */
public class App {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(100);
        List<Task> tasks = new ArrayList<>();
        for (int i = 0; i < 1_000; i++) {
            tasks.add(new Task(i));
        }
        long time = System.currentTimeMillis();
        List<Future<Integer>> futures = executor.invokeAll(tasks);
        long sum = 0;
        for (Future<Integer> future : futures) {
            sum += future.get();
        }
        time = System.currentTimeMillis() - time;
        System.out.println("sum = " + sum + "; time = " + time + " ms");
        executor.shutdown();
    }
}

运行结果如下

Thread pool-1-thread-1 - Task 0 waiting...
Thread pool-1-thread-3 - Task 2 waiting...
Thread pool-1-thread-2 - Task 1 waiting...
……
sum = 49879; time = 10142 ms

接下来,我们用虚拟线程测试整个事情。因此,我们只需要替换这一行

ExecutorService executor = Executors.newFixedThreadPool(100);

替换为

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

执行效果如下

Thread  - Task 0 waiting...
Thread  - Task 2 waiting...
Thread  - Task 3 waiting...
……
sum = 48348; time = 1125 ms

1125 ms VS 10142 ms,性能提升非常明显。

注:本示例需要在 JDK 19 下运行,且需要增加 --enable-preview 参数,在 IDEA 下,这个参数配置如下

image

image

我们已经了解了创建虚拟线程的一种方法:使用Executors.newVirtualThreadPerTaskExecutor()创建的执行器服务,为每个任务创建一个新的虚拟线程。

使用Thread.startVirtualThread()Thread.ofVirtual().start(),我们也可以明确地启动虚拟线程。

Thread.startVirtualThread(() -> {
  // code to run in thread
});

Thread.ofVirtual().start(() -> {
  // code to run in thread
});

特别说明:Thread.ofVirtual()返回一个VirtualThreadBuilder,其start()方法启动一个虚拟线程。另一个方法Thread.ofPlatform()返回一个PlatformThreadBuilder,通过它我们可以启动一个平台线程。

这两种构造方法都实现了Thread.Builder接口。这使得我们可以编写灵活的代码,在运行时决定它应该在虚拟线程还是平台线程中运行。

源码

hello-virtual-thread

参考资料

Java 19 Features (with Examples)

JDK 19 Release Notes

Virtual Threads in Java (Project Loom)

标签:Task,Java,Thread,19,虚拟,线程
From: https://www.cnblogs.com/greyzeng/p/16732227.html

相关文章

  • 1、什么是JavaScript,有什么特点,作用是什么?
    1.JavaScript是基于对象和事件驱动的解释性脚本语言2.基于对象:js是一种基于对象的语言,这意味着它能运用自己已经创建的对象,因此,许多功能可以来自脚步环境种对象的方法与......
  • java service/web前端解决跨域( CORS policy: Response to preflight request doesn't
    1、什么是跨域?跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。所谓同源是指,域名,协议,端口均相同,只要有一个不同,就是跨域......
  • Java 进阶
    Java进阶1.数组1.1数组的创建注意:new是在堆中创建一个数组或者在堆中分配一块连续的存储空间,把这块空间的引用赋值给数组名还有需要注意的是,数组定义了之后,系统会给......
  • Java 狂神 Day01 Windows快捷键
    Windows快捷键ctrl+E:打开我的电脑ctrl+shift+esc:打开任务管理器alt+F4:关闭窗口alt+tab:切换窗口shift+del:永久删除win+D:返回桌面 ......
  • javascrip的随机应用 ,和练习案例
    //Math.random()//Math.random()返回0(包括)至1(不包括)之间的随机数:varzxc=Math.random()console.log(zxc);//Math......
  • 虚拟线程
    Java19新特性:虚拟线程(VirtualThreads)......
  • java JDBC 读取MySQL数据
    1、准备1、mysql成功启动2、准备好jdbc驱动包,根据mysql选择版本,mysql-connector-java-5.1.46.jar  --》Stringdriver="com.mysql.jdbc.Driver";mysql-c......
  • 日常拉会-“浪费”时间的无形降本(2022年9月19日-9月23日)
        上一次周报《会议-存在即有价值》中有说道,很多人都在说:“今天啥也没干,净开会了”、“一天总共没多长时间,全浪费在开会上了”、“会议多,意义还不大”等等,最终有......
  • JavaScript手写函数
     //url的queryString转成对象functionqueryStr2Obj(url){constquery={};constsearch=url.split('?')[1];if(!search){return{}......
  • 【Java基础】内部类
    1.内部类在一个类的内部再定义一个类,内部类和外部类名字不能相同。可以分为成员内部类:静态、非静态局部内部类:方法内、代码块内、构造器内,匿名内部类2.成员内部类(1......