參考:Thread.join的作用和原理
參考:Thread類中的join()方法原理
文章目錄
-
- 一.start方法和run方法差別
-
- 1.先看總結
- 2.源碼分析
- 二.join:線程串行
- 三.interrupt:告知停止方法
-
- 1.如何安全地停止線程?
-
- 1.循環标記變量自定義一個共享的boolean類型變量,表示目前線程是否需要中斷。
- 2.循環中斷狀态中斷辨別 由線程對象提供,無需自己定義。
- 四.sleep和wait差別
一.start方法和run方法差別
1.先看總結
start() : 它的作用是啟動一個新線程,新線程會執行相應的run()方法。start()不能被重複調用。
run() : run()就和普通的成員方法一樣,可以被重複調用。單獨調用run()的話,會在目前線程中執行run(),而并不會啟動新線程!
2.源碼分析
start方法:
public synchronized void start() {
//1.如果這個線程已經被系統調用了就直接報錯,也就是說這個線程不能成功start兩次
if (threadStatus != 0)
throw new IllegalThreadStateException();
//2.往線程組中添加這個線程
group.add(this);
boolean started = false;
try {
//3.調用native的啟動方法,真正的啟動線程
start0();
started = true;
} finally {
try {
//4.線程啟動失敗要從group移除
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
run方法:
@Override
public void run() {
//1.直接啟動Runnable的繼承類的run方法,隻是方法調用,不是真正的線程調用
if (target != null) {
target.run();
}
}
二.join:線程串行
Thread類中的join方法的主要作用就是同步,它可以使得線程之間的并行執行變為串行執行
例如,A線程中調用了B線程的join方法,則相當于A線程調用了B線程的wait方法,在調用了B線程的wait方法後,A線程就會進入阻塞狀态
/**
* 我們來着這樣的一段代碼.
* Thread A(){
* @overrite
* run(){
* Thread b = new Thread();
* b.start();
* b.join();
* }
* }
* 這個方法就相當于在A線程中調用了B線程的wait方法,因為join就是會循環去執行wait.這樣的話就會讓A線程進入等待
* 直到B線程執行結束之後才會調用notify方法去喚醒A線程
* @param millis 等待時間
* @throws InterruptedException
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
//1.如果等待時間是0,就會循環一直等待
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
//2.如果目前線程存活,這邊計算wait的時間.
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
三.interrupt:告知停止方法
方法說明:
- 将調用者線程的中斷狀态設為true。:public void interrupt()
- 判斷調用者線程的中斷狀态。:public boolean isInterrupted()
- 隻能通過Thread.interrupted()調用。 它會做兩步操作:傳回目前線程的中斷狀态;将目前線程的中斷狀态設為false:public static boolean interrupted
1.如何安全地停止線程?
stop函數停止線程過于暴力,它會立即停止線程,不給任何資源釋放的餘地,兩種安全停止線程的方法。
1.循環标記變量自定義一個共享的boolean類型變量,表示目前線程是否需要中斷。
中斷辨別:
volatile boolean interrupted = false;
任務執行函數:
Thread t1 = new Thread( new Runnable(){
public void run(){
while(!interrupted){
// 正常任務代碼……
}
// 中斷處理代碼……
// 可以在這裡進行資源的釋放等操作……
}
} );
中斷函數:
Thread t2 = new Thread( new Runnable(){
public void run(){
interrupted = true;
}
} );
2.循環中斷狀态中斷辨別 由線程對象提供,無需自己定義。
任務執行函數:
Thread t1 = new Thread( new Runnable(){
public void run(){
while(!Thread.currentThread.isInterrupted()){
// 正常任務代碼……
}
// 中斷處理代碼……
// 可以在這裡進行資源的釋放等操作……
}
} );
中斷函數:
t1.interrupt();
上述兩種方法本質一樣,都是通過循環檢視一個共享标記為來判斷線程是否需要中斷,他們的差別在于:第一種方法的辨別位是我們自己設定的,而第二種方法的辨別位是Java提供的。除此之外,他們的實作方法是一樣的。
四.sleep和wait差別
兩個都是native方法,直接寫總結
- sleep方法是Thread類的靜态方法,wait()是Object超類的成員方法
-
sleep()方法導緻了程式暫停執行指定的時間,讓出cpu該其他線程,但是他的監控狀态依然保持者,當指定的時間到了又會自動恢複運作狀态。在調用sleep()方法的過程中,線程不會釋放對象鎖。
調用wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,隻有針對此對象調用notify()方法後本線程才進入對象鎖定池準備
- sleep方法需要抛異常,wait方法不需要