Thread.sleep蝎抽、Object.wait、LockSupport.park 區(qū)別

圖片的話看不到可以我CSDN上的博客:
https://blog.csdn.net/u013332124/article/details/84647915

在java語言中,可以通過3種方式讓線程進入休眠狀態(tài)樟结,分別是Thread.sleep()养交、Object.wait()LockSupport.park()方法瓢宦。這三種方法的表現(xiàn)和原理都各有不同碎连,今天稍微研究了下這幾個方法的區(qū)別。

Thread.sleep() 方法

Thread.sleep(time)方法必須傳入指定的時間驮履,線程將進入休眠狀態(tài)鱼辙,通過jstack輸出線程快照的話此時該線程的狀態(tài)應(yīng)該是TIMED_WAITING,表示休眠一段時間玫镐。

另外倒戏,該方法會拋出InterruptedException異常,這是受檢查異常恐似,調(diào)用者必須處理杜跷。

通過sleep方法進入休眠的線程不會釋放持有的鎖,因此矫夷,在持有鎖的時候調(diào)用該方法需要謹慎葛闷。

Object.wait() 方法

我們都知道,java的每個對象都隱式的繼承了Object類双藕。因此每個類都有自己的wait()方法淑趾。我們通過object.wait()方法也可以讓線程進入休眠。wait()有3個重載方法:

public final void wait() throws InterruptedException;
public final native void wait(long timeout) throws InterruptedException;
public final native void wait(long timeout) throws InterruptedException;

如果不傳timeout忧陪,wait將會進入無限制的休眠當(dāng)中扣泊,直到有人喚醒他。使用wait()讓線程進入休眠的話嘶摊,無論有沒有傳入timeout參數(shù)旷赖,線程的狀態(tài)都將是WAITING狀態(tài)。

另外更卒,必須獲得對象上的鎖后,才可以執(zhí)行該對象的wait方法稚照。否則程序會在運行時拋出IllegalMonitorStateException異常蹂空。

Object waitObject = new Object();
try {
    //沒獲取到waitObject的鎖,調(diào)用該方法拋出IllegalMonitorStateException異常
      waitObject.wait();
} catch (InterruptedException e) {
      e.printStackTrace();
}

//正確的調(diào)用方式  
Object waitObject = new Object();
try {
    //先獲取到waitObject的鎖
    synchronized (waitObject){
        waitObject.wait();
    }
} catch (InterruptedException e) {
      e.printStackTrace();
}

再調(diào)用wait()方法后果录,線程進入休眠的同時上枕,會釋放持有的該對象的鎖,這樣其他線程就能在這期間獲取到鎖了弱恒。

調(diào)用Object對象的notify()或者notifyAll()方法可以喚醒因為wait()而進入等待的線程辨萍。

LockSupport.park() 方法

通過LockSupport.park()方法,我們也可以讓線程進入休眠。它的底層也是調(diào)用了Unsafe類的park方法

//Unsafe.java類
//喚醒指定的線程
public native void unpark(Thread jthread);
//isAbsolute表示后面的時間是絕對時間還是相對時間锈玉,time表示時間爪飘,time=0表示無限阻塞下去
public native void park(boolean isAbsolute, long time);

調(diào)用park方法時,還允許設(shè)置一個blocker對象拉背,主要用來給監(jiān)視工具和診斷工具確定線程受阻塞的原因师崎。

調(diào)用park方法進入休眠后,線程狀態(tài)為WAITING椅棺。

實現(xiàn)原理

LockSupport.park() 的實現(xiàn)原理是通過二元信號量做的阻塞犁罩,要注意的是,這個信號量最多只能加到1两疚。我們也可以理解成獲取釋放許可證的場景床估。unpark()方法會釋放一個許可證,park()方法則是獲取許可證诱渤,如果當(dāng)前沒有許可證丐巫,則進入休眠狀態(tài),知道許可證被釋放了才被喚醒源哩。無論執(zhí)行多少次unpark()方法鞋吉,也最多只會有一個許可證。

和wait的不同

park励烦、unpark方法和wait谓着、notify()方法有一些相似的地方。都是休眠坛掠,然后喚醒赊锚。但是wait、notify方法有一個不好的地方屉栓,就是我們在編程的時候必須能保證wait方法比notify方法先執(zhí)行舷蒲。如果notify方法比wait方法晚執(zhí)行的話,就會導(dǎo)致因wait方法進入休眠的線程接收不到喚醒通知的問題友多。而park牲平、unpark則不會有這個問題,我們可以先調(diào)用unpark方法釋放一個許可證域滥,這樣后面線程調(diào)用park方法時纵柿,發(fā)現(xiàn)已經(jīng)許可證了,就可以直接獲取許可證而不用進入休眠狀態(tài)了启绰。

另外昂儒,和wait方法不同,執(zhí)行park進入休眠后并不會釋放持有的鎖委可。

對中斷的處理

park方法不會拋出InterruptedException渊跋,但是它也會響應(yīng)中斷。當(dāng)外部線程對阻塞線程調(diào)用interrupt方法時,park阻塞的線程也會立刻返回拾酝。

Thread parkThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("park begin");

                //等待獲取許可
                LockSupport.park();
                //輸出thread over.true
                System.out.println("thread over." + Thread.currentThread().isInterrupted());

            }
        });
        parkThread.start();

        Thread.sleep(2000);
        // 中斷線程
        parkThread.interrupt();

        System.out.println("main over");

上面的demo最終會輸出

park begin
main over
thread over.true

說明因park進入休眠的線程收到中斷通知后也會立刻返回燕少,并且可以手動通過Thread.currentThread().isInterrupted()獲取到中斷位。

總結(jié)

[圖片上傳失敗...(image-695f30-1543556287018)]

題外話:關(guān)于java進程的關(guān)閉

在linux中微宝,我們通常用kill命令來關(guān)閉一個進程棺亭。眾所周知,kill有-9和-15兩種參數(shù)蟋软,默認是-15镶摘。如果是-15參數(shù),系統(tǒng)就發(fā)送一個關(guān)閉信號給進程岳守,然后等待進程關(guān)閉凄敢。在這個過程中,目標進程可以釋放手中的資源湿痢,以及進行一些關(guān)閉操作涝缝。

正是有了這個概念,我曾經(jīng)很大一段時間對java進程的關(guān)閉流程有所誤解譬重。在我原先的理解中拒逮,java進程接收到關(guān)閉信號后,會逐一給阻塞中的進程發(fā)送中斷信號臀规,并等待線程處理完滩援。但其實這是錯誤的

java進程收到關(guān)閉信號后塔嬉,不會去關(guān)心運行中的那些線程是否運行完玩徊,也不會給阻塞中的線程發(fā)送中斷信號。我們只能通過綁定關(guān)閉鉤子來中斷目標線程并等待線程執(zhí)行完谨究。

final Thread waitThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread begin");

                //等待獲取許可
                try {
                    Thread.sleep(1000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //輸出thread over.true
                System.out.println("thread over." + Thread.currentThread().isInterrupted());

                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        waitThread.start();
        //綁定鉤子
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    waitThread.interrupt();
                    waitThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("shutdown success");
            }
        }));

java進程在收到關(guān)閉信號后恩袱,會執(zhí)行所有綁定了shutdownHook的線程,確保這些綁定的線程都執(zhí)行完了才真正關(guān)閉胶哲。因此畔塔,我們要釋放資源就要在shutdownHook的線程內(nèi)操作,然后在線程內(nèi)等待其他釋放資源的線程執(zhí)行完成鸯屿。

注意俩檬,所有綁定了shutdownHook的線程也是并行執(zhí)行的,不是順序執(zhí)行碾盟。另外,用-9參數(shù)的kill不會等shutdownHook線程執(zhí)行完就退出技竟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冰肴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌熙尉,老刑警劉巖联逻,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異检痰,居然都是意外死亡包归,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門铅歼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來公壤,“玉大人,你說我怎么就攤上這事椎椰∠梅” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵慨飘,是天一觀的道長确憨。 經(jīng)常有香客問我,道長瓤的,這世上最難降的妖魔是什么休弃? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮圈膏,結(jié)果婚禮上塔猾,老公的妹妹穿的比我還像新娘。我一直安慰自己本辐,他們只是感情好桥帆,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著慎皱,像睡著了一般老虫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茫多,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天祈匙,我揣著相機與錄音,去河邊找鬼天揖。 笑死夺欲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的今膊。 我是一名探鬼主播些阅,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斑唬!你這毒婦竟也來了市埋?” 一聲冷哼從身側(cè)響起嫂伞,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤若锁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凡橱,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡荧琼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年讨便,在試婚紗的時候發(fā)現(xiàn)自己被綠了育谬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡频敛,死狀恐怖项郊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姻政,我是刑警寧澤呆抑,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站汁展,受9級特大地震影響鹊碍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜食绿,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一侈咕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧器紧,春花似錦耀销、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掌腰,卻和暖如春狰住,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背齿梁。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工催植, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勺择。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓创南,卻偏偏與公主長得像,于是被迫代替她去往敵國和親省核。 傳聞我的和親對象是個殘疾皇子稿辙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 一、top(Linux命令) 執(zhí)行top命令: (查看進程15477的詳細情況气忠,下文用到) 系統(tǒng)信息(前五行): ...
    java菜閱讀 1,146評論 0 1
  • 本文是我自己在秋招復(fù)習(xí)時的讀書筆記邻储,整理的知識點未桥,也是為了防止忘記,尊重勞動成果芥备,轉(zhuǎn)載注明出處哦!如果你也喜歡舌菜,那...
    波波波先森閱讀 11,257評論 4 56
  • Java多線程學(xué)習(xí) [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,957評論 1 18
  • 莫名的倦怠日月,對自己所做的事情在潛意識中不認同袱瓮,雖然意識會刻意回避這樣的想法,也會通過理性計算來說服自己爱咬,而身體卻是...
    小幸甫閱讀 138評論 0 0
  • 一尺借、本周情境本周出差江陰,在一線協(xié)調(diào)設(shè)備調(diào)試精拟,新產(chǎn)品測試燎斩,工作圍繞產(chǎn)品測試開展。 二蜂绎、本周任務(wù)完成情況 本周高優(yōu)先...
    嚴哥閱讀 213評論 1 0