网站首页 > java教程 正文
Java 19 中的虚拟线程由 JDK 负责调度。虚拟线程创建之后,会处于不同的状态之中。这些状态包括:
- NEW:刚被创建之后的初始状态
- STARTED:线程已启动
- RUNNING:线程运行中
- PARKING:线程尝试进入停驻状态
- PARKED:线程处于停驻状态
- PINNED:线程处于锁定状态
- RUNNABLE:线程处于可运行状态
- YIELDING:线程尝试让出运行权
- TERMINATED:线程已终止
这些状态定义在 java.lang.VirtualThread 中。
private static final int NEW = 0;
private static final int STARTED = 1;
private static final int RUNNABLE = 2; // runnable-unmounted
private static final int RUNNING = 3; // runnable-mounted
private static final int PARKING = 4;
private static final int PARKED = 5; // unmounted
private static final int PINNED = 6; // mounted
private static final int YIELDING = 7; // Thread.yield
private static final int TERMINATED = 99; // final state
这些状态的变化如下图所示
在这些状态中,比较特殊的是 PARKING、PARKED、PINNED、YIELDING 等状态。这些是虚拟线程独有的。我们知道,虚拟线程与平台线程是 M 对 N 的关系。虚拟线程需要绑定到平台线程上之后才能运行。在运行过程中,如果由于某种原因无法继续执行,可以调用 VirtualThread 的 park 方法来尝试停驻,让出运行权。如果让出成功,该虚拟线程会从平台线程上解除绑定,转为停驻状态;如果让出失败,该虚拟线程会被锁定在平台线程上,导致其他虚拟线程无法使用该平台线程。
另外一种方式是应用代码主动调用 Thread.yield 来让出运行权。如果让出成功,虚拟线程会处于 RUNNABLE 状态,等待下次调度;如果让出失败,虚拟线程仍然继续运行。
Java 19 中 java.util.concurrent.locks.LockSupport 的 park 方法,会调用虚拟线程的 park 方法。这就意味着当代码因为多线程同步的原因,而无法运行时,虚拟线程会尝试停驻。
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
try {
if (t.isVirtual()) {
VirtualThreads.park();
} else {
U.park(false, 0L);
}
} finally {
setBlocker(t, null);
}
}
当虚拟线程处于锁定状态时,平台线程被该虚拟线程完全占用,会减少 JDK 调度器中可用的平台线程数量。作为调度的 ForkJoinPool 会创建新的平台线程来作为补偿,但是数量不会超过设置的最大值。
为了提高系统的吞吐量,应该尽可能地避免虚拟线程的锁定。在执行 synchronized 方法或块时,以及执行 native 方法或外部方法时,虚拟线程必定处于锁定状态。这是因为这两种方法由 JVM 来处理,JDK 的调度器无法影响这两种方法;而 Java 多线程类库中的类就没有这个问题。它们使用的是 LockSupport 中的 park 方法。当需要等待时,虚拟线程会尝试停驻而从平台线程上解除绑定,这就释放了平台线程,允许其他虚拟线程来使用,有助于提升系统的吞吐量。从这个角度来说,把 synchronized 替换成 Java 类库中的锁,可能会提升系统的吞吐量。
有几种方式可以调试虚拟线程的锁定。首先是通过系统属性 jdk.tracePinnedThreads,把该属性的值设置为 full 或者空字符串,可以在虚拟线程锁定时,输出详细的线程堆栈信息;如果该属性的值是 short,则仅输出虚拟线程的信息。
另外一种做法是使用 JFR,并监听 VirtualThreadPinnedEvent 事件,从而分析出现线程锁定的情况。
- 上一篇: 线程有哪几种状态,分别是如何切换的
- 下一篇: Java中线程的生命周期了解吗?
猜你喜欢
- 2024-12-12 Java 应用性能瓶颈剖析与多线程优化实战
- 2024-12-12 面试突击35:如何判断线程池已经执行完所有任务了?
- 2024-12-12 吞吐下降、RT增长、CPU飚高,都是 线程状态惹的祸?
- 2024-12-12 一文搞懂Java多线程
- 2024-12-12 Java线程池的关闭
- 2024-12-12 你能说出多线程中sleep、yield、join的用法及sleep与wait区别?
- 2024-12-12 队列满了、任务还在提交,看看Java线程池的任务饱和策略
- 2024-12-12 「重磅开篇」形成完善的多线程世界观
- 2024-12-12 一文深入理解java中的线程
- 2024-12-12 全局视角看技术-Java多线程演进史
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)