博文

JDK21新特性

笔者在过去主要使用的JDK版本是JDK8,最近在学习最新的JDK长期支持版本——JDK21,本文将简要记录一下JDK21相比于JDK8的一些新特性,对于一些比较有意思的新特性也会在后续文章中逐步展开研究。 var关键字局部变量推断 // 仅限局部变量适用 var name = "renxin" ; var age = 18; var isMan = true ; var list = new ArrayList < String > (); var map = new HashMap < String, String > (); switch 表达式增强 // 假设有枚举定义为 public enum Direction { EAST, SOUTH, WEST, NORTH, NORTHWEST, ; } // switch 表达式为变量赋值 var witchCity = switch (direction) { case EAST, NORTHWEST -> "成都" ; case WEST -> "上海" ; case SOUTH -> "广州" ; case NORTH -> "北京" ; default -> throw new IllegalArgumentException( "Invalid direction: " + direction); }; // yield 关键字返回值,并跳出switch表达式(相当于break) var witchCity = switch (direction) { case EAST, NORTHWEST: System. out . println ( "成都" ); yield "成都" ; case WEST: System. out . println ( ...

理解虚拟线程

JDK21中正式引入了虚拟线程,这是Java标准库首次正式支持用户态轻量级线程,它的出现让Java并发编程更加简单高效。这篇文章将深入探讨虚拟线程的概念和原理,帮助你更好的理解和使用虚拟线程。 为什么需要虚拟线程 在虚拟线程出现之前,Java中主要依靠线程(Thread)实现并发编程,通过将多个任务分配给多个线程来实现并发执行,每个线程具有独立的执行栈,一个线程就是一个并发执行单元。 而Java语言中的线程和操作系统中的线程是一一对应的,Java代码中每创建一个线程,JVM都会调用操作系统的API来创建一个操作系统线程并映射到Java线程。这种并发方式有以下特点: 创建销毁:线程的创建和销毁都由需要操作系统内核来完成,涉及用户态和内核态的切换,开销较大。 内存占用:在Linux系统上运行的JVM,每创建一个线程,JVM会为其默认分配1MB的内存空间,用于存储线程的执行栈等信息,对应的操作系统线程也会分配约10KB的内存空间用于保存操作系统线程栈,内存占用量较大。 上下文切换:线程由操作系统调度运行,每次切换线程都需要保存和恢复线程的上下文,这涉及保存和恢复大量寄存器、栈和其他状态信息,也会使CPU缓存失效,且同样涉及用户态和内核态的切换,开销较大,且过多的线程还会导致一个结果就是大量的CPU资源都消耗在调度和切换执行线程上,用到执行线程任务的比例就会变小,CPU负载也会很大。 可用数量(支持并发数):在Linux系统中,一个进程可以创建的线程数有限,又由于线程创建占用内存资源较多,调度切换执行消耗的CPU资源也大,因此可用线程数很有限,通常为数千个,因此应用所能够支持的并发任务数也有限。 基于以上几个特点,一些现代编程语言纷纷引入了“轻量线程”的概念,例如Go语言中的协程、Kotlin语言中的协程等。Java语言也终于在JDK21中正式引入了虚拟线程,这是Java标准库首次正式支持用户态轻量级线程。 虚拟线程解决了哪些问题      虚拟线程实际上是用户态的轻量级线程,有以下特点:   创建销毁:虚拟线程的创建和销毁都由JVM在用户态完成,不需要操作系统的参与,因此避免了操作系统内核态与用户态的切换带来的性能损耗。  内存占用:虚拟线程使用的内存由JVM控制,通常只需要几KB的内存空间,远小于操作系统线程的1...