J.U.C之LockSupport
一、与wait/notify区别
wait/notify 为Object中的方法,在调用这两个方法前必须要先获得对象的锁,而locksupport则无需获取对象锁就可以锁定指定线程。
nodify 只能唤醒任意线程,而locksupport 可以唤醒指定线程,且park不需要捕获中断异常,wait 需要。
二、怎么用
主要是park/unpark, park字面意思停车,形象解释为叫这个线程你站住,你停一下。unpark 就是你继续走。park 和 unpark 就是一个消耗许可和产生许可的过程。底层维护了一个计数器_counter, 多次调用unpark 只会多次将_counter置为1,而不是加1,简单说就是:线程A连续调用两次LockSupport.unpark(B)方法唤醒线程B,然后线程B调用两次LockSupport.park()方法, 线程B依旧会被阻塞。因为两次unpark调用效果跟一次调用一样,只能让线程B的第一次调用park方法不被阻塞,第二次调用依旧会阻塞。每一个线程都会维护着这样一个许可.
public static void park() {
UNSAFE.park(false, 0L);
}
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
public static void park(Object blocker); // 暂停当前线程
public static void parkNanos(Object blocker, long nanos); // 暂停当前线程,不过有超时时间的限制
public static void parkUntil(Object blocker, long deadline); // 暂停当前线程,直到某个时间
public static void park(); // 无期限暂停当前线程
public static void parkNanos(long nanos); // 暂停当前线程,不过有超时时间的限制
public static void parkUntil(long deadline); // 暂停当前线程,直到某个时间
public static void unpark(Thread thread); // 恢复当前线程
public static Object getBlocker(Thread t);
示例:
public class LockSupportTest {
public static class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程开始等待..");
LockSupport.park();
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程结束等待..");
}
}
public static void main(String[] args){
Thread _t = new MyThread();
_t.start();
System.out.println("开始唤醒线程..");
LockSupport.unpark(_t);
System.out.println("唤醒线程结束..");
}
}
输出:
开始唤醒线程..
线程开始等待..
唤醒线程结束..
线程结束等待..
public class LockSupportTest {
public static class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程开始等待..");
System.out.println("第1个park开始...");
LockSupport.park();
System.out.println("第1个park结束...");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第2个park开始..");
LockSupport.park();
System.out.println("第2个park结束..");
System.out.println("线程结束等待..");
}
}
public static void main(String[] args){
Thread _t = new MyThread();
_t.start();
System.out.println("开始唤醒线程..");
LockSupport.unpark(_t);
LockSupport.unpark(_t);
System.out.println("唤醒线程结束..");
}
}
输出: 可以看出第2个park未能获取到锁,一直等待
开始唤醒线程..
线程开始等待..
第1个park开始...
唤醒线程结束..
第1个park结束...
第2个park开始..
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律