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有效.