本文原創,轉載請標明原處!
Thread對象可操縱一個線程,而Runnable對象代表一個可被運行的對象,必須使用Thread對象的start()方法啟動線程。啟動後,會先運行Thread對象的run()方法,這個方法未被重寫時,就會執行Runnable對象的run()方法。
主線程的入口是main()靜態方法,子線程的入口是Thread的run()方法。下圖表示Thread與Runnable的區別:

線程可以在運行中暫停,也可以從暫停中恢復運行,其暫停的目有如下列舉:
下圖表示,線程基本的暫停方式與恢復運行方式:
說明:圖中,虛線表示每次觸發時,只允許一條線程變化。Happen表示發生於其它線程,即異步觸發。
有一點不太明確,也不知道怎麼去測試,就是Auto Yield,這裡我猜想加上去的。猜想的依據是根據一篇文章《Java中的多線程你只要看這一篇就夠了》。文中寫道,並行與並發的概念與區別,思考了一下,並行是多個人同時處理各自的事,換句話說同一時刻可以處理多件事。而並發是一個人同時處理多件事,但實際上是做不到的,因為同一時刻只能處理一件事。不知道這裡,我有沒有思考有誤,如果是這樣,那麼同一時刻,就只處理著一條線程。
線程結束分為自然結束與強制中止。
自然結束,是指線程啟動時的入口方法結束,自然結束分為正常結束和異常結束。異常結束是以某個異常拋出作為起點一直往上拋出,而正常結束,需要監聽到結束的標志後,處理關閉事項,需要處理上一段時間才能真正結束。
強制中止,在運行途中的任意位置結束,什麼時候中止,線程就什麼時候結束。可以使用stop()方法強制中止,也可以把把線程設置為目標線程的守護線程,這樣線程就會以目標線程結束而強制結束。強制中止,用於不需要維護重要數據的線程,即對重要數據不產生影響。
代碼示例1:主線程以子線程對象作為同步鎖,然後使用wait(...)方法,當子線程結束時,就會喚醒wait(...)方法,從而達到主線程監聽子線程的結束。
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(){
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子線程結束!");
}
};
thread.start();
// 相當於thread.join(),thread線程結束時,會調用thread.notifyAll()
synchronized(thread){
thread.wait();
}
System.out.println("主線程結束!");
// 輸出結果:
// 子線程結束!
// 主線程結束!
}
實際上,join(...)方法裡面,用的就是這種方式監聽子線程的結束。因此,主線程使用join(...)方法後,子線程要切忌不能使用自己的線程對象作為同步鎖,那樣會造成死鎖。
代碼示例2:主線程調用子線程的interrupt()方法,使子線程在wait()方法裡拋出異常,同時還驗證了interrupt()使子線程從wait()方法中喚醒後,依然需要同步阻塞。
public static void main(String[] args) throws InterruptedException {
final Object lock = new Object();
Thread[] threads = new Thread[5];
for(int i=0; i<threads.length; i++){
final int num = i + 1;
Thread thread = new Thread(){
public void run(){
synchronized(lock){
try {
System.out.println("線程" + num + " -> 進入等待!");
lock.wait();
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("線程" + num + " -> " + e);
}
System.out.println("線程" + num + " -> 退出等待!");
try {
System.out.println("線程" + num + " -> 進入睡眠!");
Thread.sleep(500);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("線程" + num + " -> " + e);
}
System.out.println("線程" + num + " -> 睡眠結束,退出同步塊!");
Thread.currentThread().stop();
System.out.println("線程" + num + " -> 結束沒有?");
}
}
};
thread.start();
threads[i] = thread;
}
System.out.println("主線程 -> 等待2秒!");
Thread.sleep(2000);
System.out.println("主線程 -> 中止所有線程!");
for(int i=0; i<threads.length; i++){
threads[i].interrupt();
}
for(int i=0; i<threads.length; i++){
threads[i].join();
}
System.out.println("主線程 -> 中止所有線程結束!");
/*
輸出結果:
線程1 -> 進入等待!
線程4 -> 進入等待!
主線程 -> 等待2秒!
線程3 -> 進入等待!
線程2 -> 進入等待!
線程5 -> 進入等待!
主線程 -> 中止所有線程!
線程1 -> 退出等待!
線程1 -> 進入睡眠!
線程1 -> 睡眠結束,退出同步塊!
線程4 -> 退出等待!
線程4 -> 進入睡眠!
線程4 -> 睡眠結束,退出同步塊!
線程3 -> 退出等待!
線程3 -> 進入睡眠!
線程3 -> 睡眠結束,退出同步塊!
線程2 -> 退出等待!
線程2 -> 進入睡眠!
線程2 -> 睡眠結束,退出同步塊!
線程5 -> 退出等待!
線程5 -> 進入睡眠!
線程5 -> 睡眠結束,退出同步塊!
主線程 -> 中止所有線程結束!
*/
}
代碼示例3:子線程作為主線程的守護線程,因主線程的結束而強制中止。
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(){
public void run(){
boolean run = true;
while(run){
System.out.println("子線程 -> 運行中……");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("子線程 -> 正常退出!");
}
};
thread.setDaemon(true);
thread.start();
System.out.println("主線程 -> 2秒後結束");
Thread.sleep(2000);
System.out.println("主線程 -> 結束");
/*
運行結果:
主線程 -> 2秒後結束
子線程 -> 運行中……
子線程 -> 運行中……
子線程 -> 運行中……
子線程 -> 運行中……
子線程 -> 運行中……
主線程 -> 結束
*/
}
待續更新……