目录
- 1. 虚拟线程(Virtual Threads)
- 2. 有序集合(Sequenced Collections)
- 3. switch 的模式匹配(Pattern Matching for switch)
- 4. 记录模式(Record Patterns)
- 5. ZGC
- 6. 准备禁用动态代理(Prepare to Disallow the Dynamic Loading of Agents)
1. 虚拟线程(Virtual Threads)
https://openjdk.org/jeps/444
- 虚拟线程是工作在平台线程之上的,虚拟线程的数量可以远大于操作系统线程的数量,多个虚拟线程挂载在一个平台线程上,一个平台线程可以在不同的时间执行不同的虚拟线程,当虚拟线程被阻塞或等待时,平台线程可以切换到执行另一个虚拟线程。
注意事项:
- 虚拟线程主要作用是提升服务器端的吞吐量,而不是提高线程的执行速度。
- 虚拟线程只适合IO密集型的任务,阻塞期间可以将CPU资源让渡给其他任务,不适合CPU密集型的任务或非阻塞任务。
- 虚拟线程是廉价且轻量级的,使用完后立即被销毁,因此不需要池化。
- 创建虚拟线程的方法
import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.stream.IntStream;
@Slf4j
public class Demo {
public static void main(String[] args) throws Exception {
Runnable task = () -> {
log.info(Thread.currentThread().toString());
};
// 1. 通过 Thread.ofVirtual() 创建
Thread thread = Thread.ofVirtual().name(Thread.currentThread().toString()).start(task);
// 2. 通过 Thread.startVirtualThread() 创建
Thread.startVirtualThread(task);
// 3. 通过 ThreadFactory 创建
ThreadFactory factory = Thread.ofVirtual().factory();
Thread newThread = factory.newThread(task);
newThread.start();
// 4. 通过 Executors.newVirtualThreadPerTaskExecutor() 创建
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 5).forEach(i -> {
executor.submit(() -> {
log.info("{}, before", Thread.currentThread());
try {
Thread.sleep(Duration.ofSeconds(1));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("{}, after", Thread.currentThread());
});
});
}
System.in.read();
}
}
- 打印
19:49:16.027 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#22]/runnable@ForkJoinPool-1-worker-2
19:49:16.027 [Thread[#1,main,5,main]] INFO org.example.virtual_thread.Demo -- VirtualThread[#20,Thread[#1,main,5,main]]/runnable@ForkJoinPool-1-worker-1
19:49:16.029 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#23]/runnable@ForkJoinPool-1-worker-2
19:49:16.029 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#25]/runnable@ForkJoinPool-1-worker-1, before
19:49:16.030 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#27]/runnable@ForkJoinPool-1-worker-2, before
19:49:16.029 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#26]/runnable@ForkJoinPool-1-worker-2, before
19:49:16.031 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#28]/runnable@ForkJoinPool-1-worker-1, before
19:49:16.031 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#29]/runnable@ForkJoinPool-1-worker-1, before
19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#27]/runnable@ForkJoinPool-1-worker-1, after
19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#25]/runnable@ForkJoinPool-1-worker-2, after
19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#28]/runnable@ForkJoinPool-1-worker-2, after
19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#26]/runnable@ForkJoinPool-1-worker-1, after
19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#29]/runnable@ForkJoinPool-1-worker-2, after
- 通过25号虚拟线程可以看出,阻塞前后使用的平台线程发生过切换
VirtualThread[#22]/runnable@ForkJoinPool-1-worker-2
表示VirtualThread[#22]这个虚拟线程依赖于平台线程ForkJoinPool-1-worker-2,这里我在VM参数中添加了-Djdk.virtualThreadScheduler.maxPoolSize=2 -Djdk.virtualThreadScheduler.parallelism=2
,限制平台线程最大2个,所以只能会看到ForkJoinPool-1-worker-1和ForkJoinPool-1-worker-2两个平台线程。
- 虚拟线程在block后,会与平台线程解绑,然后加入任务列表排队,等待分配给平台线程
2. 有序集合(Sequenced Collections)
https://openjdk.org/jeps/431
- Sequenced Collections是一种具有确定出现顺序的集合。提供了处理集合第一个和最后一个元素以及反转集合的简单方法。
Sequenced Collections 包括以下三个接口:
- SequencedCollection
- SequencedSet
- SequencedMap
interface SequencedCollection<E> extends Collection<E> {
// New Method
SequencedCollection<E> reversed();
// Promoted methods from Deque<E>
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
3. switch 的模式匹配(Pattern Matching for switch)
https://openjdk.org/jeps/441
- 属于语法方面的升级,增强了 switch 表达式,允许在 case 标签中使用模式。
- JDK21之前
// Prior to Java 21
static String formatter(Object obj) {
String formatted = "unknown";
if (obj instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (obj instanceof Long l) {
formatted = String.format("long %d", l);
} else if (obj instanceof Double d) {
formatted = String.format("double %f", d);
} else if (obj instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
- JDK21之后
// As of Java 21
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
}
4. 记录模式(Record Patterns)
https://openjdk.org/jeps/440
- 记录模式(Record Patterns) 可对 record 的值进行解构,也就是更方便地从记录类(Record Class)中提取数据。并且,记录模式和类型模式可以嵌套使用,以实现强大的、声明性的和可组合的数据导航和处理形式。
- 记录模式不能单独使用,而是要与 instanceof 或 switch 模式匹配一同使用。
- 以 instanceof 为例
// As of Java 16
record Point(int x, int y) {}
static void printSum(Object obj) {
if (obj instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
}
// As of Java 21
static void printSum(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println(x+y);
}
}
5. ZGC
https://openjdk.org/jeps/439
-
ZGC是一款低延迟、高吞吐的JVM垃圾回收器。JDK11试验版本,JDK15变为生产版本,但都是不分代的,所有的对象都存储在一起,每次垃圾回收都要回收所有对象。
在JDK21中区分年轻代和老年代,因为年轻代的对象存活时间更短,所以 通过提高收集年轻代的对象的频率迅速释放JVM内存。 -
默认不开启ZGC,可以使用以下命令开启
java -XX:+UseZGC -XX:+ZGenerational
6. 准备禁用动态代理(Prepare to Disallow the Dynamic Loading of Agents)
https://openjdk.org/jeps/451
- 当代理被动态加载到运行中的 JVM 时发出警告。这些警告的目的是让用户做好准备,以便在未来的版本中默认禁止动态加载代理。
动态代理允许开发人员在运行时修改和监视Java应用程序,存在潜在的安全风险,例如窃取敏感信息、篡改数据等。因此,为了加强Java应用程序的安全性,限制动态加载代理的使用是有必要的。