線程間的交互和通信
-
一個(gè)線程啟動(dòng)另一個(gè)線程
public static void main(String[] args){ new Thread().start(); }主線程啟動(dòng)另一個(gè)線程。
-
一個(gè)線程終結(jié)另個(gè)一線程
A.Thread.stop()來停止一個(gè)線程,但是已經(jīng)被棄用了,因?yàn)?code>stop結(jié)果是不可預(yù)期的,它是直接將線程干掉了,即是你的業(yè)務(wù)剛執(zhí)行到一半,這樣就導(dǎo)致結(jié)果是不可預(yù)期的,比較危險(xiǎn)。Thread thread = new Thread(); thread.start(); thread.stop();B.
Thread.interrupt()來中斷一個(gè)線程的執(zhí)行。它的原理是調(diào)用interrupt方法后,將該線程編輯為中斷狀態(tài),需要我們自己處理這個(gè)狀態(tài)。Thread thread = new Thread(){ @Override public void run(){ if(isInterrupted()){ //do something } } }; thread.start(); thread.interrupt();判斷一個(gè)線程是否標(biāo)記為中斷狀態(tài),可以使用
thread.isInterrupted(),也可以使用Thead的靜態(tài)方法Thread.interruped(),二者的區(qū)別是前者可以重復(fù)多次使用,后者只能使用一次,因?yàn)槭褂弥髸?huì)將標(biāo)記復(fù)位,即置為false,實(shí)際使用根據(jù)自己具體的邏輯來具體使用哪種方式。C. 當(dāng)一個(gè)線程正在休眠中,此時(shí)被中斷,會(huì)怎樣?
答案是會(huì)立即拋出InterruptedException,然后線程會(huì)被立即結(jié)束,但是中斷標(biāo)志一直是false。因?yàn)楫?dāng)處于休眠狀態(tài),說明這個(gè)線程目前沒有在處理事情,也就是說可以立即打斷,也不會(huì)產(chǎn)生影響,所以會(huì)被立即終止。這也是當(dāng)我們寫Thread.sleep(10);的時(shí)候要求強(qiáng)制捕獲InterruptedException的原因,所以如果我們有需要?jiǎng)t要在異常中處理中斷的后續(xù)邏輯。 -
兩個(gè)線程互相配合
需要使用wait()和notify()以及notifyAll(),這里有必要說明下,這3個(gè)方法是針對monitor來說的,并不是針對線程,需要等的是monitor,需要喚醒的也是monitor,和線程無關(guān),而且這3個(gè)方法也必須是在同步代碼塊中才可以使用。
下面我們來簡單說一下wait和notify的工作模型。
工作模型
首先我們看下這段代碼,有兩個(gè)同步方法methodA和methodB,他們的鎖對象都是this,即monitor是同一個(gè),下面來說明下這個(gè)工作模型。
當(dāng)ThreadA先訪問methodB時(shí),它先來到等待訪問排隊(duì)區(qū),發(fā)現(xiàn)里面沒人,就他自己,于是它從monitor那里拿到了鎖,此時(shí)的線程正在訪問區(qū)里面放的是ThreadA。但是methodB里面的代碼是wait(),此時(shí)monitor會(huì)將ThreadA放到右面的等待喚醒區(qū),同時(shí)ThreadA所持有的鎖也會(huì)被釋放,正在訪問區(qū)是空的。這時(shí)ThreadB來了,想訪問methodA,它問了下monitor,我可以訪問methodA嗎,因?yàn)榇藭r(shí)的ThreadA的鎖已經(jīng)釋放了,它理所當(dāng)然的可以訪問methodA,此時(shí)的線程正在訪問區(qū)中里面放的是ThreadB, ThreadB拿著鎖來到了methodA內(nèi)部,此時(shí)它發(fā)現(xiàn)里面是notifyAll,所以此時(shí)的monitor就將等待喚醒區(qū)里面的所有等待喚醒的線程都喚醒了,然后ThreadB就是放了鎖,然后罵罵咧咧的走了,此時(shí)線程正在訪問區(qū)是空的。等待喚醒區(qū)中的ThreadA被喚醒,他只能再次來到等待訪問排隊(duì)區(qū),不能插隊(duì)到正在訪問區(qū)中,只能公平的再次去競爭鎖,然后發(fā)下排隊(duì)的就他自己,于是它又從monitor那里拿到了鎖,然后就去訪問methodB了,但是里面又是wait(),于是乎它又釋放鎖,然后又進(jìn)入了等待喚醒區(qū),可以沒有人再去訪問methodA來告訴monitor區(qū)喚醒喚醒等待區(qū)里面的線程了,此時(shí)ThreadA將永遠(yuǎn)在等待喚醒區(qū)等一輩子。
大致的一個(gè)工作模型就是這樣的,可能描述的不太清楚,但是大致原理是清晰的,相信多看幾遍總會(huì)明白的,哈哈哈。。。
這里為什么調(diào)用的是nitofyAll呢,而不是notify呢?因?yàn)獒槍@個(gè)monitor而言,有可能等待喚醒區(qū)有好多個(gè)線程正在等待,而不是一個(gè),如果只喚醒一個(gè),那剩下的咋辦?所以只能一次性喚醒所有的,除非你明確知道等待喚醒區(qū)中只有一個(gè)線程在等待被喚醒。
所以從這個(gè)工作模型來看,wait,notify 以及notifyAll 都是針對monitor而言的,是monitor讓一個(gè)線程區(qū)等待喚醒區(qū),也是monitor來進(jìn)行喚醒等待喚醒區(qū)里面的線程,而且wait和notify一定是成對出現(xiàn)的。
下面舉一個(gè)簡單的栗子。
public class Demo {
public static void main(String[] args) {
new WaitNotifyTest().runTest();
}
private static class WaitNotifyTest{
private int x;
void runTest() {
Thread threadA = new Thread(){
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
plus();
}
};
threadA.start();
Thread threadB = new Thread(){
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
printX();
}
};
threadB.start();
}
private synchronized void plus() {
x++;
notifyAll();
}
private synchronized void printX() {
if (x == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("The x is: " + x);
}
}
}
執(zhí)行結(jié)果如下:

- 插隊(duì)
將一個(gè)線程插到當(dāng)前線程之前執(zhí)行,插隊(duì)的方法就是join。
簡單代碼如下:public static void main(String[] args) { Thread threadA = new Thread(){ @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("run method in ThreadA class is finished。"); } }; threadA.start(); try { threadA.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main method is finished。"); }上述代碼執(zhí)行的結(jié)果:
執(zhí)行結(jié)果
當(dāng)ThreadA執(zhí)行了join插隊(duì)方法后,main方法所在的線程會(huì)等ThradA線程執(zhí)行結(jié)果后在執(zhí)行。
join可以說是簡化后的wait,notify,只是不需要我們調(diào)用notify。
它的作用時(shí)將并行的兩個(gè)線程變成串行化。
-
yield。暫時(shí)讓出時(shí)間片,讓給同優(yōu)先級的線程,這個(gè)時(shí)間很短很短,讓出之后馬上會(huì)再次獲取到時(shí)間片。
由于個(gè)人能力有限,如有錯(cuò)誤之處,還望指出,我會(huì)第一時(shí)間驗(yàn)證并修改。
理解事物,看本質(zhì)。共勉。

