LockSupport是什么
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,其中park()和unpack()而作用分别是阻塞线程
和解除阻塞线程
.
线程等待唤醒机制
三种让线程等待和唤醒的方法
- 方式一:使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程
- 方式二:使用JUC包中的Condition的await()方法让线程等待,使用signal()方法唤醒线程
- 方式三:LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程
Object类中的wait和notify方法实现线程等待和唤醒
局限性:
- wait和notify方法必须要在
同步代码块
或者同步方法
里面,且成对出现使用 - 先wait再notify才ok
/**
* Object类中的wait和notify方法实现线程等待和唤醒演示
* @create 2023-04-11 12:13
*/
public class LockSupportDemo {
public static void main(String[] args) {
Object objectLock = new Object();
/**
* t1 -----------come in
* t2 -----------发出通知
* t1 -------被唤醒
*/
new Thread(() -> {
synchronized (objectLock) {
System.out.println(Thread.currentThread().getName() + "\t -----------come in");
try {
objectLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t -------被唤醒");
}
}, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
synchronized (objectLock) {
objectLock.notify();
System.out.println(Thread.currentThread().getName() + "\t -----------发出通知");
}
}, "t2").start();
}
}
Condition接口中的await和signal方法实现线程的等待和唤醒
局限性:
- Condition中的线程等待和唤醒方法,需要
先获取锁
- 一定要先await后signal,不要反了
/**
* Condition接口中的await和signal方法实现线程的等待和唤醒演示
* @create 2023-04-11 12:13
*/
public class LockSupportDemo {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
/**
* t1 -----------come in
* t2 -----------发出通知
* t1 -----------被唤醒
*/
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t -----------come in");
condition.await();
System.out.println(Thread.currentThread().getName() + "\t -----------被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t -----------发出通知");
} finally {
lock.unlock();
}
}, "t2").start();
}
}
上述两个对象Object和Condition使用的限制条件
- 线程需要先获得并持有锁,必须在
锁块(synchronized或lock)
中 - 必须要先等待后唤醒,线程才能够被唤醒
所以需要引入LockSupport
LockSupport类中的park等待和unpark唤醒
- 是什么
-
- LockSupport 是用于创建锁和其他同步类的
基本线程阻塞原语
- LockSupport类使用了一种名为
Permit(许可)
的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(Permit),许可证只能有一个,累加上限是1
。
- LockSupport 是用于创建锁和其他同步类的
- 主要方法
-
- 阻塞: Peimit许可证默认没有不能放行,所以一开始调用park()方法当前线程会阻塞,直到别的线程给当前线程发放peimit,park方法才会被唤醒。
-
-
- park/park(Object blocker)-------阻塞当前线程/阻塞传入的具体线程
-
-
- 唤醒: 调用unpack(thread)方法后 就会将thread线程的许可证peimit发放,会自动唤醒park线程,即之前阻塞中的LockSupport.park()方法会立即返回。
-
-
- unpark(Thread thread)------唤醒处于阻塞状态的指定线程
-
- 代码
/**
* LockSupport类中的park等待和unpark唤醒演示
* @create 2023-04-11 12:13
*/
public class LockSupportDemo {
public static void main(String[] args) {
/**
* t1 -----------come in
* t2 ----------发出通知
* t1 ----------被唤醒
*/
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t -----------come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t ----------被唤醒");
}, "t1");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
LockSupport.unpark(t1);
System.out.println(Thread.currentThread().getName() + "\t ----------发出通知");
}, "t2").start();
}
}
- 重点说明(重要)
-
- LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,所有的方法都是
静态方法
,可以让线程再任意位置阻塞,阻塞后也有对应的唤醒方法。归根结底,LockSupport时调用Unsafe
中的native代码 - LockSupport提供park()和unpark()方法实现阻塞线程和解除线程阻塞的过程,LockSupport和每个使用它的线程都有一个许可(Peimit)关联,每个线程都有一个相关的permit,peimit最多只有一个,重复调用unpark也不会积累凭证。
- 形象理解:线程阻塞需要消耗凭证(Permit),这个凭证最多只有一个
- LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,所有的方法都是
-
-
- 当调用park时,如果有凭证,则会直接消耗掉这个凭证然后正常退出。如果没有凭证,则必须阻塞等待凭证可用;
- 当调用unpark时,它会增加一个凭证,但凭证最多只能有
1个
,累加无效。
-
- 面试题
-
- 为什么LockSupport可以突破wait/notify的原有调用顺序?
-
-
- 因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞,先发放了凭证后续可以畅通无阻。
-
-
- 为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
-
-
- 因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证,而调用两次park却需要消费两个凭证,证不够,不能放行。
-