1.背景
面试官问,如何暂停一个线程勒.....
说说你对park的理解.......
2.代码
package com.ldp.demo01; import com.common.MyThreadUtil; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.locks.LockSupport; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 02/01 10:58 * @description <p> * park & unpark 与 wait & notify 相比 * 1.wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用,而 park,unpark 不必 * 2.park & unpark 是以线程为单位来 阻塞 和 唤醒 线程,而 notify 只能随机唤醒一个等待线程,notifyAll 是唤醒所有等待线程,就不那么 精确 * 3.park & unpark 可以先 unpark,而 wait & notify 不能先 notify * </p> */ @Slf4j public class Test04UnPark { /** * 1.先park在unPark * 2.先unPark 在park---(会导致第一次park无效) * <p> * park的理解(非常重要) * <p> * 每个线程都有自己的一个 Parker 对象, * 由三部分组成 _counter(计数器) , _cond (聚光器,这里相当于休息室) 和 _mutex (互斥量) * <p> * 打个比喻 * 线程就像一个旅人,Parker 就像他随身携带的背包, _cond好比背包中的帐篷。_counter就好比背包中的备用干粮(0 为耗尽,1 为充足) * <p> * 调用 park 就是要看需不需要停下来歇息 * 如果备用干粮耗尽(_counter=0),那么进入帐篷休息 * 如果备用干粮充足(_counter=1),那么不需停留,继续前进 * <p> * <p> * 调用 unpark,就好比补充干粮(不论调用多少次都只能补充一次) * 如果这时线程还在帐篷中休息,就唤醒让他继续前进 * 如果这时线程正在运行中,那么下次他调用 park 时,仅是消耗掉备用干粮(即这次unpark补充的干粮),不需停留继续前进 * 因为背包空间有限,多次调用 unpark 仅会补充一份备用干粮 * <p> * <p> * 直接解释就是: * 每个线程都有自己的一个 Parker 对象, * 由三部分组成 _counter(计数器) , _cond (聚光器,这里相当于休息室) 和 _mutex (互斥量) * <p> * <p> * 当调用 park想暂停线程时 * 如果在这之前没有调用unpark,就直接暂停当前线程. * 如果在这之前调用了unpark,线程继续运行,相当于这个park无效. * <p> * <p> * 当调用 unpark想让线程继续运行时 * 如果线程是处于暂停状态,线程被唤醒开始执行; * 如果线程本来就处于运行状态,线程继续运行,并且会记住这次unpark,线程下次park时无效. * 多次调用unpark时仅一次unpark有效. * * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { log.info("t1......1"); // 2秒后继续执行 MyThreadUtil.sleep(2); // 暂停当前线程 LockSupport.park(); log.info("t1......2"); LockSupport.park(); log.info("t1......3"); LockSupport.park(); log.info("t1......4"); }, "t1"); t1.start(); // 2秒后继续执行 // MyThreadUtil.sleep(2); // 回复运行中的状态 LockSupport.unpark(t1); log.info("unpark......1"); LockSupport.unpark(t1); log.info("unpark......2"); } }
3.区别
park & unpark 与 wait & notify 相比
1.wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用,而 park,unpark 不必
2.park & unpark 是以线程为单位来 阻塞 和 唤醒 线程,而 notify 只能随机唤醒一个等待线程,notifyAll 是唤醒所有等待线程,就不那么 精确
3.park & unpark 可以先 unpark,而 wait & notify 不能先 notify
4.原理理解
每个线程都有自己的一个 Parker 对象,
由三部分组成 _counter(计数器) , _cond (聚光器,这里相当于休息室) 和 _mutex (互斥量)
4.1.比喻理解
线程就像一个旅人,Parker 就像他随身携带的背包, _cond好比背包中的帐篷。_counter就好比背包中的备用干粮(0 为耗尽,1 为充足)
调用 park 就是要看需不需要停下来歇息
如果备用干粮耗尽(_counter=0),那么进入帐篷休息
如果备用干粮充足(_counter=1),那么不需停留,继续前进
调用 unpark,就好比补充干粮(不论调用多少次都只能补充一次)
如果这时线程还在帐篷中休息,就唤醒让他继续前进
如果这时线程正在运行中,那么下次他调用 park 时,仅是消耗掉备用干粮(即这次unpark补充的干粮),不需停留继续前进
因为背包空间有限,多次调用 unpark 仅会补充一份备用干粮
4.2.直接解释
每个线程都有自己的一个 Parker 对象,
由三部分组成 _counter(计数器) , _cond (聚光器,这里相当于休息室) 和 _mutex (互斥量)
当调用 park想暂停线程时
如果在这之前没有调用unpark,就直接暂停当前线程.
如果在这之前调用了unpark,线程继续运行,相当于这个park无效.
当调用 unpark想让线程继续运行时
如果线程是处于暂停状态,线程被唤醒开始执行;
如果线程本来就处于运行状态,线程继续运行,并且会记住这次unpark,线程下次park时无效.
多次调用unpark时仅一次unpark有效.