複製代碼代碼如下:
// 開始執行緒
public void start( );
public void run( );
// 掛起和喚醒線程
public void resume( ); // 不建議使用
public void suspend( );// 不建議使用
public static void sleep(long millis);
public static void sleep(long millis, int nanos);
// 終止執行緒
public void stop( ); // 不建議使用
public void interrupt( );
// 得到執行緒狀態
public boolean isAlive( );
public boolean isInterrupted( );
public static boolean interrupted( );
// join方法
public void join( ) throws InterruptedException;
一、創建並運行線程
執行緒在建立後不會馬上執行run方法中的程式碼,而是處於等待狀態。當執行緒處於等待狀態時,可以透過Thread類別的方法來設定執行緒不各種屬性,如執行緒的優先權(setPriority)、執行緒名(setName)和執行緒的類型(setDaemon)等。
當呼叫start方法後,執行緒開始執行run方法中的程式碼。執行緒進入運行狀態。可以透過Thread類別的isAlive方法來判斷執行緒是否處於運行狀態。當執行緒處於運行狀態時,isAlive傳回true,當isAlive回傳false時,可能執行緒處於等待狀態,也可能處於停止狀態。下面的程式碼示範了執行緒的建立、運行和停止三個狀態之間的切換,並輸出了對應的isAlive回傳值。
複製代碼代碼如下:
package chapter2;
public class LifeCycle extends Thread
{
public void run()
{
int n = 0;
while ((++n) < 1000);
}
public static void main(String[] args) throws Exception
{
LifeCycle thread1 = new LifeCycle();
System.out.println("isAlive: " + thread1.isAlive());
thread1.start();
System.out.println("isAlive: " + thread1.isAlive());
thread1.join(); // 等執行緒thread1結束後再繼續執行
System.out.println("thread1已經結束!");
System.out.println("isAlive: " + thread1.isAlive());
}
}
要注意一下,在上面的程式碼中使用了join方法,這個方法的主要功能是確保執行緒的run方法完成後程式才繼續運行,這個方法將在後面的文章中介紹
上面程式碼的運行結果:
isAlive: false
isAlive: true
thread1已經結束!
isAlive: false
二、掛起和喚醒線程
一但執行緒開始執行run方法,就會一直到這個run方法執行完成這個執行緒才退出。但在執行緒執行的過程中,可以透過兩個方法使執行緒暫時停止執行。這兩個方法是suspend和sleep。使用suspend掛起執行緒後,可以透過resume方法喚醒執行緒。而使用sleep讓執行緒休眠後,只能在設定的時間後讓執行緒處於就緒狀態(在執行緒休眠結束後,執行緒不一定會馬上執行,只是進入了就緒狀態,等待系統進行調度)。
雖然suspend和resume可以很方便地使線程掛起和喚醒,但由於使用這兩個方法可能會造成一些不可預料的事情發生,因此,這兩個方法被標識為deprecated(抗議)標記,這表明在在以後的jdk版本中這兩個方法可能會被刪除,所以盡量不要使用這兩個方法來操作線程。下面的程式碼示範了sleep、suspend和resume三個方法的使用。
複製代碼代碼如下:
package chapter2;
public class MyThread extends Thread
{
class SleepThread extends Thread
{
public void run()
{
try
{
sleep(2000);
}
catch (Exception e)
{
}
}
}
public void run()
{
while (true)
System.out.println(new java.util.Date().getTime());
}
public static void main(String[] args) throws Exception
{
MyThread thread = new MyThread();
SleepThread sleepThread = thread.new SleepThread();
sleepThread.start(); // 開始執行執行緒sleepThread
sleepThread.join(); // 使執行緒sleepThread延遲2秒
thread.start();
boolean flag = false;
while (true)
{
sleep(5000); // 使主執行緒延遲5秒
flag = !flag;
if (flag)
thread.suspend();
else
thread.resume();
}
}
}
從表面上看,使用sleep和suspend所產生的效果類似,但sleep方法並不等同於suspend。它們之間最大的一個區別是可以在一個線程中透過suspend方法來掛起另外一個線程,如上面程式碼中在主線程中掛起了thread線程。而sleep只對目前正在執行的執行緒起作用。在上面程式碼中分別使sleepThread和主執行緒休眠了2秒和5秒。在使用sleep時要注意,不能在一個執行緒中來休眠另一個執行緒。如main方法中使用thread.sleep(2000)方法是無法使thread執行緒休眠2秒的,而只能使主執行緒休眠2秒。
在使用sleep方法時有兩點需要注意:
1. sleep方法有兩個重載形式,其中一個重載形式不僅可以設毫秒,而且還可以設奈秒(1,000,000奈秒等於1毫秒)。但大多數作業系統平台上的Java虛擬機都無法精確到奈秒,因此,如果對sleep設定了奈秒,Java虛擬機將取最接近這個值的毫秒。
2. 使用sleep方法時必須使用throws或try{...}catch{...}。因為run方法無法使用throws,所以只能用try{...}catch{...}。當在執行緒休眠的過程中,使用interrupt方法(這個方法將在2.3.3中討論)中斷執行緒時sleep會拋出一個InterruptedException例外。 sleep方法的定義如下:
複製代碼代碼如下:
public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException
三、終止執行緒的三種方法
有三種方法可以使終止執行緒。
1. 使用退出標誌,使執行緒正常退出,也就是run方法完成後執行緒終止。
2. 使用stop方法強行終止執行緒(這個方法不建議使用,因為stop和suspend、resume一樣,也可能發生不可預料的結果)。
3. 使用interrupt方法中斷執行緒。
1. 使用退出標誌終止線程
當run方法執行完後,執行緒就會退出。但有時run方法是永遠不會結束的。如在服務端程式中使用執行緒進行監聽客戶端請求,或是其他的需要循環處理的任務。在這種情況下,一般是將這些任務放在一個循環中,如while循環。如果想要讓迴圈永遠運作下去,可以使用while(true){...}來處理。但要使while循環在某一特定條件下退出,最直接的方法就是設一個boolean類型的標誌,並透過設定這個標誌為true或false來控制while循環是否退出。下面給了一個利用退出標誌終止執行緒的例子。
複製代碼代碼如下:
package chapter2;
public class ThreadFlag extends Thread
{
public volatile boolean exit = false;
public void run()
{
while (!exit);
}
public static void main(String[] args) throws Exception
{
ThreadFlag thread = new ThreadFlag();
thread.start();
sleep(5000); // 主執行緒延遲5秒
thread.exit = true; // 終止執行緒thread
thread.join();
System.out.println("線程退出!");
}
}
在上面程式碼中定義了一個退出標誌exit,當exit為true時,while循環退出,exit的預設值為false。在定義exit時,使用了一個Java關鍵字volatile,這個關鍵字的目的是讓exit同步,也就是說在同一時刻只能由一個執行緒來修改exit的值,
2. 使用stop方法終止線程
使用stop方法可以強行終止正在執行或掛起的執行緒。我們可以使用如下的程式碼來終止執行緒:
thread.stop();
雖然使用上面的程式碼可以終止線程,但使用stop方法是很危險的,就像突然關閉電腦電源,而不是按正常程式關機一樣,可能會產生不可預料的結果,因此,並不建議使用stop方法來終止線程。
3. 使用interrupt方法終止執行緒
使用interrupt方法來終端執行緒可分為兩種情況:
(1)執行緒處於阻塞狀態,如使用了sleep方法。
(2)使用while(!isInterrupted()){...}來判斷執行緒是否被中斷。
在第一種情況下使用interrupt方法,sleep方法將拋出一個InterruptedException例外,而在第二種情況下執行緒將直接退出。下面的程式碼示範了在第一種情況下使用interrupt方法。
複製代碼代碼如下:
package chapter2;
public class ThreadInterrupt extends Thread
{
public void run()
{
try
{
sleep(50000); // 延遲50秒
}
catch (InterruptedException e)
{
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws Exception
{
Thread thread = new ThreadInterrupt();
thread.start();
System.out.println("在50秒之內按任意鍵中斷執行緒!");
System.in.read();
thread.interrupt();
thread.join();
System.out.println("執行緒已經退出!");
}
}
上面程式碼的運行結果如下:
複製代碼代碼如下:
在50秒之內按任意鍵中斷線程!
sleep interrupted
線程已經退出!
在呼叫interrupt方法後, sleep方法拋出異常,然後輸出錯誤訊息:sleep interrupted。
注意:在Thread類別中有兩個方法可以判斷執行緒是否透過interrupt方法被終止。一個是靜態的方法interrupted(),一個是非靜態的方法isInterrupted(),這兩個方法的區別是interrupted用來判斷當前線是否被中斷,而isInterrupted可以用來判斷其他執行緒是否被中斷。因此,while (!isInterrupted())也可以換成while (!Thread.interrupted())。