(7)LockSupport

作用

用來創(chuàng)建鎖和其他同步類的基本線程阻塞的原語.它的核心函數(shù)為parkunpack.

  • park:阻塞線程.在線程出現(xiàn)下面的情況之前都將保持阻塞.

    1. 調(diào)用unpack釋放該線程的許可.
    2. 線程被中斷.
    3. 指定等待時間到了.
  • unpack:釋放線程許可.簡單的說就是激活調(diào)用pack進(jìn)入阻塞的線程.

pack還提供了一個帶參方法park(Object blocker),blocker用來代表使當(dāng)前線程進(jìn)入等待的對象.

在查看AbstractQueuedSynchronizer(AQS)中,發(fā)現(xiàn)其底層就是使用LockSupport.park()LockSupport.unpark()實現(xiàn)線程的阻塞和喚醒的.它的作用與Object上的wait和notify很像,但是還是存在一些不同.

不需要在同步代碼塊中調(diào)用

之前在java多線程之wait和notify中有講過,使用wait()和notify()必須在同步代碼快中才是調(diào)用,如果不是則會拋出IllegalMonitorStateException異常.但是LockSupport.park()則沒有該限制.下面示例代碼,如果去掉synchronized同步代碼塊將拋出異常.

public class App1 {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lock){
                try {
                    lock.wait();
                    System.out.println(Thread.currentThread().getName()+":執(zhí)行完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t1");
        t1.start();

        Thread t2 = new Thread(() -> {
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":執(zhí)行完成");
        }, "t2");
        t2.start();

        Thread.sleep(1000L);
        //喚醒t1,t2
        synchronized (lock){
            lock.notify();
        }
        LockSupport.unpark(t2);
    }
}

調(diào)用先后不會導(dǎo)致死鎖

在使用wait和notify時,如果線程A先調(diào)用了notify,然后線程B再調(diào)用的wait沒有指定超時時間,那么線程B將一直處于WAITING狀態(tài),直到有其他線程調(diào)用notify或者notifyAll.使用park和unpark則不會導(dǎo)致該情況發(fā)生.代碼如下:

public class App2 {

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (lock){
                System.out.println(Thread.currentThread().getName()+":開始執(zhí)行");
                lock.notify();
            }
            synchronized (lock){
                try {
                    lock.wait();
                    System.out.println(Thread.currentThread().getName()+":執(zhí)行完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+":開始執(zhí)行");
            LockSupport.unpark(Thread.currentThread());
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":執(zhí)行完成");

        }, "t2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

響應(yīng)中斷的不同

使用wait使線程進(jìn)入WAITING或者TIMED_WAITING,如果中斷線程,線程將拋出中斷異常InterruptedException.如果使用park使線程進(jìn)入等待狀態(tài),并不會拋出中斷異常.

public class App3 {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (lock){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread thread = Thread.currentThread();
                    System.out.println(thread.getName()+":響應(yīng)中斷退出");
                }
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            LockSupport.park();
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+":響應(yīng)中斷退出");
        }, "t2");

        t1.start();
        t2.start();
        Thread.sleep(1000L);
        System.out.println("t1.getState() = " + t1.getState());
        System.out.println("t2.getState() = " + t2.getState());
        t1.interrupt();
        t2.interrupt();
    }
}

不可重入

LockSupport很類似于二元信號量(只有1個許可證可供使用),如果這個許可還沒有被占用,當(dāng)前線程獲取許可并繼續(xù)執(zhí)行;如果許可已經(jīng)被占用,當(dāng)前線程阻塞,等待獲取許可.如果調(diào)用unpark多次釋放許可,再多次調(diào)用park獲取許可只能獲取到一次許可.如下面代碼,第二次調(diào)用park將導(dǎo)致線程永遠(yuǎn)的等待下去.

public class App4 {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println("第一次調(diào)用unpark");
        LockSupport.unpark(thread);
        System.out.println("第二次調(diào)用unpark");
        LockSupport.unpark(thread);
        System.out.println("第一次調(diào)用park");
        LockSupport.park();
        System.out.println("第二次調(diào)用park");
        LockSupport.park();
        System.out.println("執(zhí)行完成");
    }
}

上面示例代碼永遠(yuǎn)也不會打印執(zhí)行完成.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乏苦,一起剝皮案震驚了整個濱河市面粮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绑洛,老刑警劉巖狂丝,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夕膀,死亡現(xiàn)場離奇詭異,居然都是意外死亡美侦,警方通過查閱死者的電腦和手機产舞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菠剩,“玉大人易猫,你說我怎么就攤上這事【咦常” “怎么了准颓?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵哈蝇,是天一觀的道長。 經(jīng)常有香客問我攘已,道長炮赦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任样勃,我火速辦了婚禮吠勘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘峡眶。我一直安慰自己剧防,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布辫樱。 她就那樣靜靜地躺著峭拘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狮暑。 梳的紋絲不亂的頭發(fā)上鸡挠,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天境析,我揣著相機與錄音疟羹,去河邊找鬼缘缚。 笑死泽西,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的含长。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼译株!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起挺益,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤歉糜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后望众,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匪补,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年烂翰,在試婚紗的時候發(fā)現(xiàn)自己被綠了夯缺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡甘耿,死狀恐怖踊兜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情佳恬,我是刑警寧澤捏境,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布于游,位于F島的核電站,受9級特大地震影響垫言,放射性物質(zhì)發(fā)生泄漏贰剥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一筷频、第九天 我趴在偏房一處隱蔽的房頂上張望蚌成。 院中可真熱鬧,春花似錦截驮、人聲如沸笑陈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涵妥。三九已至,卻和暖如春坡锡,著一層夾襖步出監(jiān)牢的瞬間蓬网,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工鹉勒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帆锋,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓禽额,卻偏偏與公主長得像锯厢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子脯倒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359