Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

Java19中引入了虚拟线程,虽然默认是关闭的,但是可以以Preview模式启用,这绝对是一个重大的更新,今天Java架构杂谈带大家开箱验货,看看这家伙实现了什么了不起的功能 。
1 为什么需要虚拟线程?小张贪小便宜,在路边摊花一块钱买了一笼热气腾腾的小笼包 , 下肚之后肚子疼得不行,于是在公司找坑位 。扫了几层楼,没找到一个坑位,坑里面的人要么在抽烟,要么在外放刷视频、要么肠道不是很顺畅,蹲了半天没拉出来 。小张很鄙视在坑位里面不干正事的行为,此刻,与小张一同排队等坑位的还有几个同事...

Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

文章插图
小张突然感受到了从菊花传来的一股无法压制的推力,像极了JVM发生OOM前一刻的症状 。在这千钧一发的时刻 , 小张爆发了 。
Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

文章插图
他把在厕所里面抽烟刷视频拉不出来的人全部都赶出来了,急着释放内存的同事立刻进行解决了 , 然后趁味道还没消散 , 立刻再让出坑位把抽烟的人赶进去接着抽 。
Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

文章插图
坑位就是操作系统的线程,以前一个同事蹲坑之后 , 就占了坑位了,其他同事无法使用 。而用了虚拟线程后 , 谁要是在厕所里面刷视频、抽烟就会被赶出来,避免占用资源,这就是虚拟线程的好处 。
虚拟线程在Project Loom项目中已经孵化很久了,现在 Project Loom 的JEP 425: 虚拟线程可以在Java 19中以预览的方式使用了 , 接下来Java架构杂谈就带大家深入地了解一下它 。
在一个高并发系统中 , 给每个请求创建一个线程来处理,是很不可取的,Java线程对应一个操作系统线程 , 而操作系统线程资源是比较宝贵的 。但是如果没有开启这么多线程,又无法处理这么多请求,特别是遇到一些锁、IO、系统调用等操作时 , 需要更长的时间来处理请求 。我们一般的的做法是引入线程池 , 但是线程池也是有限制的,假设以下场景:
线程池设置为100个线程,一个请求需要花费两秒,而大部分时间都花在了IO上,那么每秒最多可以响应50个请求 。此时,CPU可能利用率很低,因为系统需要花费大部分时间来执行IO等待 。
我们以往只能通过各种响应式框架来克服这个问题 。但是引入了响应式编程框架后,代码将会变得越来越复杂,看看以下SpringCloud Gateway的源码,当你想调试它时,你会感到抓狂:
@Overridepublic Mono<Void> handle(ServerWebExchange exchange) {if (this.handlerMappings == null) {return createNotFoundError();}if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {return handlePreFlight(exchange);}return Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange)).next().switchIfEmpty(createNotFoundError()).flatMap(handler -> invokeHandler(exchange, handler)).flatMap(result -> handleResult(exchange, result));}为了使用响应式编程,你不仅需要试图接受这些难以阅读的代码 , 而且数据库程序和其他外部服务的驱动程序也必须支持响应式模式 。
现在 , 有了虚拟线程,你可以不用写这种反人类的代码了 。
接下来,Java架构杂谈带您深入浅出彻底弄懂虚拟线程是怎么回事 。
2 什么是虚拟线程?通过使用虚拟线程,可以让我们继续编写易于阅读和可维护性好的高性能代码 。从Java的角度来看,虚拟线程跟普通的线程没有什么区别,但是虚拟线程与操作系统线程并不是一对一的关系 。
2.1 虚拟线程模型虚拟线程有一个所谓的载体线程池,虚拟线程临时映射到该线程池上,一旦虚拟线程遇到阻塞操作,虚拟线程就从载体线程中移除,然后载体线程就可以执行其他新的虚拟线程或者之前阻塞后恢复的虚拟线程了 。
载体线程与虚拟线程的关系如下图所示 , 一个载体线程上面可以运行很多虚拟线程 , 每当虚拟线程变为非Runnable状态时,就从载体线程上卸载:
Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

文章插图
可以看到,虚拟线程中的阻塞操作不在阻塞正在执行的线程,这允许我们使用少量的载体线程并行处理大量的请求 。
虚拟线程的载体线程是ForkJoinPool在 FIFO 模式下运行的线程 。此池的大小默认为可用处理器的数量,可以使用系统属性

推荐阅读