LockSupport详解
简介
- LockSupport用来创建锁或其他同步类的基本线程阻塞原语.
- 调用
park()
方法时,当前线程将等待,直到获取许可. - 调用
unpark()
方法时,必须将等待获得许可的线程作为参数,使得等待的线程继续进行.
核心方法
Unsafe类的park和unpark
LockSupport的park()
和unpark()
是调用Unsafe类的park()
和unpark()
实现的.
park()
:阻塞线程.unpark()
:释放线程,激活调用park()
后阻塞的线程.
park()方法
// 调用park后线程会被阻塞,三种情况下线程获得许可:
// 1. 其他线程调用此线程的unpark()
// 2. 其他线程中断此线程
// 3. 该调用无理由返回
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); // 设置当前线程的blocker
UNSAFE.park(false, 0L); // 阻塞当前线程
setBlocker(t, null); // 设置当前线程的blocker为null
}
注:(调用两次设置blocker的原因)
首次设置好blocker后,调用park()阻塞线程,等待其他线程调用unpark()来激活线程.
当前线程再次被激活后,再次设置blocker为null.否则,在获取blocker时,得到的是上一次设置的blocker.
parkNanos
在许可可用前阻塞当前线程,最多等待指定的等待时间.
parkUntil
在指定时限前禁止当前线程,除非许可可用.
unpark
- 若给定线程的许可不可用,则使其可用,解除阻塞状态.
- 若线程未启动,则无效果.
使用park/unpark实现线程同步
示例:
// 一个park阻塞的线程,被其他线程unpark()后继续执行
threadA t1 = new threadA();
t1.start();
LockSupport.unpark(t1);
// t1.interrupt(); // 中断park的线程也可将其唤醒
// --------------------
class threadA{
Thread.sleep(1000); // 先unpark,再park一样可行
LockSupport.park();
System.out.println(Thread.currentThread().getName());
}
// 先对一个线程unpark(),然后其调用park()后,线程继续执行
threadA t1 = new threadA();
t1.start();
LockSupport.unpark(t1);
// t1.interrupt(); // 中断park的线程也可将其唤醒
// --------------------
class threadA{
LockSupport.park();
System.out.println(Thread.currentThread().getName());
}
小结
Thread.sleep()与Object.wait()的区别
Thread.sleep() |
Object.wait() |
|
---|---|---|
锁 | 不会释放占有的锁 | 会释放占有的锁 |
参数 | 必须传入睡眠的时间 | 可以传时间,也可不传 |
时间 | 时间到了会自动唤醒,继续执行 | 没有时间,需要等待notify 唤醒;有时间,则被唤醒或时间到了自动唤醒 |
Thread.sleep()与Condition.await()的区别
基本相同,Condition.await()
是调用LockSupport.part()
阻塞当前线程.
流程:
- 将当前线程加入条件队列.
- 释放锁.
- 调用
LockSupport.park()
阻塞当前线程.
Thread.sleep()和LockSupport.park()的区别
Thread.sleep() |
LockSupport.park() |
|
---|---|---|
功能 | 阻塞当前线程,不释放占有的锁 | 阻塞当前线程,不释放占有的锁 |
唤醒 | 只能自己唤醒自己 | 可以被其他线程通过unpark() 唤醒 |
异常 | 声明抛出异常 | 不需要捕获异常 |
Object.wait()和LockSupport.park()的区别
Object.wait() |
LockSupport.park() |
|
---|---|---|
使用 | 只能在synchronized块执行 | 在任意地方执行 |
异常 | 声明抛出中断异常 | 不需要捕获异常 |
超时 | 不带超时,需要其他线程执行notify() 唤醒 |
不带超时,需要其他线程执行unpark() 唤醒 |
睡眠前唤醒 | 抛出异常 | 不会被阻塞,跳过park() ,继续执行 |
参考: