Java多線程 – 控制線程
一、join
線程
像人類社會,人有很多時間都在等別人,線程也是一樣,有的時候,線程也需要等待別的線程。Thread
提供了讓一個線程等待另一個線程完成的方法,那就是 join
方法,當在某個程序執行流中調用其他線程的join()
方法,調用線程則會被阻塞,知道join()
方法加入的join
線程執行完成爲止。
join()
方法通常由使用線程的程序調用,以將大問題劃分成許多小問題,每個小問題分配一個線程,當所有小問題都得到處理之後,在再調用主線程進一步進行操作。
class demo{
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
for(int i = 0; i < 100; i++){
if(i == 20){
MyThread myThread1 = new MyThread();
//main線程調用了myThread1線程中的join的方法,所以main線程必須等到其執行結束之後才能執行。
myThread1.start();
myThread1.join();
}
System.out.println(Thread.currentThread().getName());
}
}
}
class MyThread extends Thread{
private int i;
@Override
public void run(){
for(int i = 0; i < 100; i++){
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
本程序之中有三個線程在運行,其中main
線程在一開始就調用了myThread
線程,所以它與main
是併發執行,但是main
線程調用了myThread1
線程的join方法,所以他不會與main
線程併發執行,而是直到其運行結束。
其中join()
方法有三種重載:
1. join()
:等待join
的線程運行結束。
2. join(long millis)
:等待join
線程的時間最長爲millis
秒,在millis
毫秒之內還未執行結束,則不再等待。
3. join(long millis, int nanos)
:等待join
線程的時間最長爲millis
毫秒加nanos
毫微妙。
二、後臺線程
有一類線程,他是在後臺運行,任務是爲了其他線程提供服務的,這類線程成爲“後臺線程”,也成爲“守護線程”或者“精靈線程”,其中在JVM中,垃圾回收線程就是最典型的後臺線程。
後臺線程的特徵:如果所有的前臺線程都死亡,則後臺線程會自動死亡。
設置方法:調用Thread
對象的setDaemon(true)
方法可以將指定線程設置爲後臺線程,當所有前臺的線程都死亡的時候,後臺線程的存在也沒有用處了,此時後臺進程也沒有繼續運行下去的必要了,所以程序也截止了。
注意:前臺線程死亡之後,JVM會通知後臺線程死亡,但是從它接收指令再到做出指令,需要一定時間,且將某個線程設置爲後臺線程,需要再線程啓動之前設置,也就是說需要再setDaemon(true)
必須要在start()
方法之前調用,否則會引發IllegalThreadStateException
異常。
三、線程睡眠Sleep()
如果需要當前執行的線程暫停一段時間,進入阻塞狀態,則可以調用Thread
類的靜態方法sleep()
方法來實現。
> static void sleep(long millis)
:讓當前正在執行線程暫停millis
毫秒,並且進入阻塞狀態,該方法收到系統計時器和線程調度器的精度和準確度影響。
> static void sleep(long millis, int nanos)
:讓正在執行的線程暫停millis
毫秒加nanos
毫微妙,並且進入阻塞狀態,該方法收到系統計時器和線程調度器的精度和準確度影響。
當線程調用阻塞狀態後,在其睡眠時間端內,線程不會獲得執行的機會,即使此時系統中沒有其他的可執行線程,處於sleep()
的線程也不會影響。
此外,Thread
還提供了一個與sleep()
方法類似的yield()
靜態方法,也可以讓當前的程序暫停,但是卻不會阻塞線程,知識將線程轉爲就緒狀態,。yield()
只是將當前線程暫停一下,讓系統的線程調度器重新調度一下,完全可能的情況是,當某個線程調用該方法暫停之後,線程調度器又將其調度出來重新執行。
實際,線程調用yield()
暫停之後,只有優先級與當前線程相同,或者優先級比當前線程更高的處於就緒狀態的線程纔會獲得執行的機會。
sleep()
方法和yield()
方法區別:
sleep()
方法將暫停當前線程之後,給其他線程執行機會,不會理會其他線程的優先級;yield()
方法只會給優先級相同,或者優先級更大的線程執行機會。sleep()
方法會將線程轉入阻塞狀態,知道經過阻塞時間,纔會轉入就緒狀態,yield()
方法強制當前線程直接進入就緒狀態。很可能某線程被轉入就緒狀態之後,立即再次獲取處理器資源被執行。sleep()
方法聲明跑出InterruptedException
異常,butyield()
方法並未聲明跑出任何異常。sleep()
方法比yield()
方法有更加好的可移植性,但是通常不建議使用yield()
方法來控制併發線程的執行。
四、改變線程優先級
每個線程都會擁有一定的優先級,優先級高的線程獲得較多的執行機會,優先級低的線程則獲得較少的執行機會
每個線程的優先級默認與創建它的父線程優先級相同,默認情況:main
線程擁有普通優先級。
Thread
類提供了setPriority(int newPriority)
、getPriority()
方法設置和返回線程的優先級,優先級範圍是1-10。
靜態常量名 | 值 |
---|---|
MAX_PRIORITY |
10 |
MIN_PRIORITY |
5 |
NORM_PRIORITY |
1 |