虚拟线程探索与实践

这篇具有很好参考价值的文章主要介绍了虚拟线程探索与实践。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

优质博文:IT-BLOG-CN

一、简介

虚拟线程是轻量级线程,极大地减少了编写、维护和观察高吞吐量并发应用的工作量。虚拟线程是由JEP 425提出的预览功能,并在JDK 19中发布,JDK 21中最终确定虚拟线程,以下是根据开发者反馈从JDK 20中的变化:
【1】jdk21中虚拟线程始终支持线程本地变量。与在预览版本中允许的不同,现在不再可能创建不能具有线程本地变量的虚拟线程。对线程本地变量的有保障支持确保了许多现有库可以不经修改地与虚拟线程一起使用,并有助于将以任务为导向的代码迁移到使用虚拟线程。
【2】直接使用Thread.Builder API创建的虚拟线程(而不是通过Executors.newVirtualThreadPerTaskExecutor()创建的虚拟线程)现在默认情况下也会在其生命周期内进行监控,并且可以通过描述在"观察虚拟线程"部分中的新线程转储来观察。

基于协程的线程,与其他语言中的协程有相似之处,也有不同。虚拟线程是依附于主线程的,如果主线程销毁了,虚拟线程也不复存在。

二、背景

1、大量应用时同步方式,修改成异步方式投入资源大;
2、由线程池被打满引起的事故很难杜绝,很多应用将核心和非核心的应用一起交由线程池管理;

解决上面问题有两种措施:
1、NIO:优点是有成熟框架ReactorRxJava等。缺点是可读性欠缺,改造难度大;
2、虚拟线程:优点是业务侧改造成本低,无需池化,天然隔离。缺点是对nativesynchronize方法或者外部函数不友好;

三、原理

调度方式: 当前线程将任务提交给虚拟线程的时候,是一个Runnalbe状态,存放在队列中排队。任务排到第一位后,会挂在到平台线程上Platform Thread,该线程就是用户线程New Thread的线程。当任务挂载上去之后,就是一个运载线程,执行虚拟线程中的任务。当线程执行到阻塞或者IO操作的时候,它会将当前任务卸载到队列中,重新编程Runnable状态。

虚拟线程探索与实践,Java并发编程(多线程),java,redis,数据库,面试,后端,性能优化,系统架构

状态机: 与平台的线程的状态相似,我们主要看下如下两个状态的变化

RUNNING -> PARKING 与普通线程一致,通常由各种block导致 触发后置为PARKING状态,卸载虚拟线程,调用Continuation.yield()方法
RUNNING -> YIELDING 通常为IO阻塞时 置为YIELDING状态,卸载虚拟线程,调用Thread.yield

虚拟线程探索与实践,Java并发编程(多线程),java,redis,数据库,面试,后端,性能优化,系统架构

四、使用场景

计算密集型

CPU机密型: 并行开启X个任务,每个任务对5W个随机数进行排序;

虚拟线程探索与实践,Java并发编程(多线程),java,redis,数据库,面试,后端,性能优化,系统架构

结论:虚拟线程对于CPU密集型应用无优势

IO密集型

并发数 CPU 响应时间(ms) 吞吐量
10 35 19 490
20 55 20 925
30 80 22 1296
40 95 26 1468
50 99 32 1508

结论:虚拟线程在CPU使用率达到80以后,性能有些许衰退。

虚拟线程探索与实践,Java并发编程(多线程),java,redis,数据库,面试,后端,性能优化,系统架构

结论: 相同的并发下
1、由于虚拟线程不需要大量的系统线程调度,节省了CPU的开销;
2、系统线程的大量减少,减少了CPU_Load排队的情况;
3、虚拟线程替换了dal的线程池,减少了线程数量(上面包含了JVM自身的线程和框架的线程);

使用案例代码:

CDubboClient instance = CDubboClient.getInstance();
FlightPassengerWS service = instance.getService(FlightPassengerWS.class);
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    StudentResponseType studentResponse = executor.submit( () -> service.getStudent(request).get());
}

五、死锁

synchronize同步代码块导致的死锁现象:

虚拟线程探索与实践,Java并发编程(多线程),java,redis,数据库,面试,后端,性能优化,系统架构

结论: 虚拟线程获取了连接后IO发生了卸载,当链接数耗尽,装载状态的虚拟线程由于拿不到链接被BLOCK,发生yield。由于在同步代码块中,yield失败发生绑定。导致其他获取链接的虚拟线程无运载线程可用。

解决办法: 使用ReentrantLock替换Synchronized

private final ReentranLock synLock = new ReentranLock();
synchronized(this) {

}
// 替换为
synLock.lock();
try {

} finally {
    synLock.unlock();
}

六、实践

QPS 1000+ 的项目性能监控

平台线程 虚拟线程
CPU使用率(avg) 20% 15%
CPU_Load(max) 15 5.5
线程数(avg) 260 258
时间响应(avg) 118ms 97ms
P99.9 3460ms 1676ms

使用虚拟线程后,由于切换了线程,无法从HttpContext.current()获取到任何信息,需要在虚拟线程里threadlocal重新set文章来源地址https://www.toymoban.com/news/detail-805887.html

到了这里,关于虚拟线程探索与实践的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java并发编程】变量的线程安全分析

    1.成员变量和静态变量是否线程安全? 如果他们没有共享,则线程安全 如果被共享: 只有读操作,则线程安全 有写操作,则这段代码是临界区,需要考虑线程安全 2.局部变量是否线程安全 局部变量是线程安全的 当局部变量引用的对象则未必 如果给i对象没有逃离方法的作用

    2024年02月08日
    浏览(53)
  • Java面试_并发编程_线程基础

    进程是正在运行程序的实例, 进程中包含了线程, 每个线程执行不同的任务 不同的进程使用不同的内存空间, 在当前进程下的所有线程可以共享内存空间 线程更轻量, 线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程) 并发是单个

    2024年02月07日
    浏览(49)
  • 【Java并发编程】线程中断机制(辅以常见案例)

    本文由浅入深介绍了中断机制、中断的常见案例和使用场景。 因为一些原因需要取消原本正在执行的线程。我们举几个栗子: 假设踢足球点球时,A队前4轮中了4个球,B队前4轮只中了2个球,此时胜负已分,第5轮这个点球就不用踢了,此时需要停止A队的线程和B队的线程(共

    2024年02月13日
    浏览(35)
  • java并发编程:多线程基础知识介绍

    最初的计算机只能接受一些特定的指令,用户每输入一个指令,计算机就做出一个操作。当用户在思考或者输入时,计算机就在等待。这样效率非常低下,在很多时候,计算机都处在等待状态。 后来有了 批处理操作系统 ,把一系列需要操作的指令写下来,形成一个清单,一次

    2024年02月07日
    浏览(49)
  • Java21虚拟线程实践

      就在前几天,java21正式版发布了,作为继java17之后的又一个长期支持版本 (LTS),为我们带来了很多新的特性,其中我最感兴趣的就是虚拟线程(virtual thread),相信大家对虚拟线程也很好奇。趁着空闲时间安装了jdk21来体验一把,顺便把我查到的关于java21虚拟线程相关的资料

    2024年02月08日
    浏览(42)
  • Java并发编程学习16-线程池的使用(中)

    上篇分析了在使用任务执行框架时需要注意的各种情况,并简单介绍了如何正确调整线程池大小。 本篇将继续介绍对线程池进行配置与调优的一些方法,详细如下: ThreadPoolExecutor 为 Executors 中的 newCachedThreadPool 、 newFixedThreadPool 和 newScheduledThreadExecutor 等工厂方法返回的 Exe

    2024年02月10日
    浏览(42)
  • Java并发编程学习笔记(一)线程的入门与创建

    认识 程序由指令和数据组成,简单来说,进程可以视为程序的一个实例 大部分程序可以同时运行多个实例进程,例如记事本、画图、浏览器等 少部分程序只能同时运行一个实例进程,例如QQ音乐、网易云音乐等 一个进程可以分为多个线程,线程为最小调度单位,进程则是作

    2024年02月16日
    浏览(51)
  • Java并发编程第6讲——线程池(万字详解)

    Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池,本篇文章就详细介绍一下。 定义:线程池是一种用于管理和重用线程的技术(池化技术),它主要用于提高多线程应用程序的性能和效率。 ps:线程池、连接池、内存池

    2024年02月11日
    浏览(39)
  • Java并发编程(三)线程同步 上[synchronized/volatile]

    当使用多个线程来访问同一个数据时,将会导致数据不准确,相互之间产生冲突,非常容易出现线程安全问题,比如多个线程都在操作同一数据,都打算修改商品库存,这样就会导致数据不一致的问题。 所以我们通过线程同步机制来保证线程安全,加入同步锁以避免在该线程没有完成

    2024年02月13日
    浏览(41)
  • Java并发编程学习18-线程池的使用(下)

    上篇介绍了 ThreadPoolExecutor 配置和扩展相关的信息,本篇开始将介绍递归算法的并行化。 还记得我们在《Java并发编程学习11-任务执行演示》中,对页面绘制程序进行一系列改进,这些改进大大地提供了页面绘制的并行性。 我们简单回顾下相关的改进过程: 第一次新增时,页

    2024年02月12日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包