前言
今天簡單的講一講線程中sleep(),join(),yield(),wait(),notify(),notifyAll()這些方法的使用以及區(qū)別豹爹。
不過在講這些方法之前榴徐,需要簡單的介紹一下鎖池和等待池的概念膳灶。
專欄推薦:
并發(fā)編程專欄
鎖池和等待池
1.鎖池
所有需要競爭同步鎖的線程都會放在鎖池當(dāng)中嚎莉,比如當(dāng)前對象的鎖已經(jīng)被其中一個線程得到悯搔,則其他線程需要在這個鎖池進(jìn)行等待灾常,當(dāng)前面的線程釋放同步鎖后鎖池中的線程去競爭同步鎖,當(dāng)某個線程得到后會進(jìn)入就緒隊列進(jìn)行等待cpu資源分配鲫惶。
2.等待池
當(dāng)我們調(diào)用wait()方法后蜈首,線程會放到等待池當(dāng)中实抡,等待池的線程是不會去競爭同步鎖欠母。只有調(diào)用了notify()或notifyAll()后等待池的線程才會開始去競爭鎖欢策,notify()是隨機(jī)從等待池選出一個線程放到鎖池,而notifyAll()是將等待池的所有線程放到鎖池當(dāng)中
sleep()
首先看一下sleep方法的源碼赏淌,我們發(fā)現(xiàn)sleep是一個靜態(tài)方法踩寇,它接受一個long類型的毫秒值參數(shù),而且是一個本地方法(native修飾)六水,而且會拋出InterruptedException(中斷異常)俺孙。
sleep()這個方法的使用很簡單,因為它是一個Thread的靜態(tài)方法掷贾,所以就可以直接Thread.sleep(毫秒值)睛榄,休眠指定的毫秒數(shù)。
1想帅、使當(dāng)前線程(即調(diào)用該方法的線程)暫停執(zhí)行一段時間场靴,讓其他線程有機(jī)會執(zhí)行。但是時間到了之后線程會進(jìn)入就緒隊列港准,重新去競爭cpu資源旨剥。
2.sleep()會釋放cpu資源,但是不會釋放同步鎖(類鎖和對象鎖)
例如有兩個線程同時執(zhí)行(沒有synchronized)一個線程優(yōu)先級為MAX_PRIORITY浅缸,另一個為MIN_PRIORITY轨帜,如果沒有Sleep()方法,只有高優(yōu)先級的線程執(zhí)行完畢后衩椒,低優(yōu)先級的線程才能夠執(zhí)行蚌父;但是高優(yōu)先級的線程sleep(500)后,低優(yōu)先級就有機(jī)會執(zhí)行了毛萌。
總之梢什,sleep()可以使低優(yōu)先級的線程得到執(zhí)行的機(jī)會,當(dāng)然也可以讓同優(yōu)先級朝聋、高優(yōu)先級的線程有執(zhí)行的機(jī)會嗡午。
yield()
使當(dāng)前正在執(zhí)行的線程向另一個線程交出運行權(quán)。注意這是一個靜態(tài)方法冀痕。
該方法與sleep()類似荔睹,只是不能由用戶指定暫停多長時間,并且yield()方法只能讓同優(yōu)先級的線程有執(zhí)行的機(jī)會言蛇。
1僻他、yield()執(zhí)行后線程直接進(jìn)入就緒狀態(tài)。
2腊尚、yield()會釋放cpu資源吨拗,但是不會釋放同步鎖(類鎖和對象鎖)
join()
執(zhí)行后線程進(jìn)入阻塞狀態(tài),例如在線程B中調(diào)用線程A的join(),那線程B會進(jìn)入到阻塞隊列劝篷,直到j(luò)oin結(jié)束或中斷線程B才開始進(jìn)入阻塞隊列哨鸭。
可以實現(xiàn)一個線程的順序執(zhí)行。
下面舉一個小例子:
我排隊打飯,smile女神來了,我讓她先打飯娇妓,但是這個時候她男朋友來了像鸡,smile女神讓他男朋友先打飯。嗚嗚嗚~~~~
public class UseJoin {
static class Smile implements Runnable {
private Thread thread;
public Smile(Thread thread) {
this.thread = thread;
}
public Smile() {
}
public void run() {
System.out.println("smile開始排隊打飯.....");
try {
if(thread!=null) thread.join();
} catch (InterruptedException e) {
}
SleepTools.second(2);//休眠2秒
System.out.println(Thread.currentThread().getName()
+ " smile打飯完成.");
}
}
static class SmileBoyfriend implements Runnable {
public void run() {
SleepTools.second(2);//休眠2秒
System.out.println("smileBoyfriend開始排隊打飯.....");
System.out.println(Thread.currentThread().getName()
+ " smileBoyfriend打飯完成.");
}
}
public static void main(String[] args) throws Exception {
SmileBoyfriend smileBoyfriend = new SmileBoyfriend();
Thread sbf = new Thread(smileBoyfriend);
Smile smile = new Smile(sbf);
Thread s = new Thread(smile);
s.start();//我排隊打飯
sbf.start();//smile女神來了,但是這個時候她男朋友來了哈恰,smile女神讓他男朋友先打飯
System.out.println("chaoCode開始排隊打飯.....");
s.join();
Thread.sleep(2000);//讓主線程休眠2秒
System.out.println(Thread.currentThread().getName() + " chaoCode打飯完成.");
}
}
執(zhí)行結(jié)果只估,可想而知,抱抱可憐的自己着绷。
wait()和notify()蛔钙、notifyAll()
1、wait方法用于協(xié)調(diào)多個線程對共享數(shù)據(jù)的存取荠医,所以必須在Synchronized語句塊內(nèi)使用
2夸楣、wait()方法使當(dāng)前線程暫停執(zhí)行并釋放會cpu資源,以及同步鎖(類鎖和對象鎖)
3子漩、調(diào)用wait()后必須調(diào)用notify()或notifyAll()后線程才會從等待池進(jìn)入到鎖池豫喧,當(dāng)我們的線程競爭得到同步鎖后就會重新進(jìn)入緒狀態(tài)等待cpu資源分配
當(dāng)調(diào)用notify()方法后,將從對象的等待池中移走一個任意的線程并放到鎖標(biāo)志等待池中幢泼,只有鎖標(biāo)志等待池中線程能夠獲取鎖標(biāo)志紧显;如果鎖標(biāo)志等待池中沒有線程,則notify()不起作用缕棵。
notifyAll()則從對象等待池中移走所有等待那個對象的線程并放到鎖標(biāo)志等待池中孵班。
注意:
1、這三個方法都是java.lang.Object的方法招驴。
2篙程、notif()方法要配合wait()方法使用,一般在wait()之后調(diào)用或者在線程結(jié)束時調(diào)用才會成功别厘。
感謝諸君的觀看虱饿,文中如有紕漏,歡迎在評論區(qū)來交流触趴。如果這篇文章幫助到了你氮发,歡迎點贊??關(guān)注。