# 線程的生命周期
[TOC]
## 線程的狀態
線程存在五個狀態:
* 創建狀態(new)
* 就緒狀態(runnable)
* 運行狀態(running)
* 阻塞狀態(blocked)
* 終止狀態(dead)

>[warning]需要注意的是,stop()方法現已不建議使用了
## 狀態詳解
* **創建狀態**
在程序中使用構造方法創建一個線程對象后,新的線程對象便處于新建狀態。此時,它已經有了相應的內存空間和其他資源,但還是處于不可運行狀態。
比如可以`Thread myThread = new Thread();`
* **就緒狀態**
新建線程對象后,調用該線程的`start()`方法就可以啟動線程,當線程啟動的時候,線程就進入就緒狀態。此時線程進入線程隊列排隊,等待CPU調度服務。
* **運行狀態**
當就緒狀態的線程被調用并獲得處理器資源時,線程就進入了運行狀態。此時將自動調用該線程對象的`run()`方法。
* **阻塞狀態**
一個正在運行的線程在某些特殊情況下,將讓出CPU并暫時停止自己的運行,進入阻塞狀態。阻塞時,線程不能進入排隊隊列,只有當引起阻塞的原因被消除后,線程才會轉入就狀態
* **終止狀態**
當線程體中的`run()`方法運行結束后,線程即處于終止狀態,處于終止狀態的線程不具有繼續運行的能力
## 線程休眠-sleep()方法的使用
休眠會使線程進入休眠狀態
`sleep()`方法是`Thread`類的靜態方法,該方法無返回值。

**作用**:在指定的毫秒數內讓正在執行線程休眠(暫停執行)
**參數**:參數為休眠的時間,單位是毫秒
~~~java
public class MyRunnable implements Runnable{
@Override
public void run() {
int i = 1;
while(i <= 30) {
//打印該線程的當前線程名稱
System.out.println(Thread.currentThread().getName()+"say:Hello,World" + i);
//休眠1000毫秒后,線程并不是立即進入可運行狀態,而是要等待CPU的調度,所以如果使用sleep寫一個時鐘類的應用可能會有一些誤差
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
}
public class MyRunnableUse {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
Thread thread1 = new Thread(myRunnable);
thread1.start();
}
}
~~~
**使用場景**:
1. 比如我們可以使用`sleep()`方法計時30秒鐘,然后一秒一秒的輸出倒計時
2. 在交通類的應用中可以使用`sleep()`方法定期刷新數據,獲取最新的交通信息
>[info]使用sleep()方法在休眠相應時間后,轉為可運行狀態,在獲取cpu使用權后進入運行狀態;這個方法可能會發生InterruptedException異常,需要強制性的使用try-catch捕獲。
## 線程強制執行-join()方法
在多線程并發執行中每一個線程對象都會交替還行,如果此時某個線程對象中的內容非常重要,需要優先執行完成,則可以設置為強制執行,待其執行完畢后其他線程再繼續執行。

`public final void join()`方法優先執行,搶占資源,該線程執行完后其他線程才能執行,該方法不允許重寫。
`public final void join(long millis)`可帶參數,等待該進程的最長時間(即該線程占用資源的時間),時間完成后該線程不再擁有優先權,正常執行
~~~
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(getName() + "線程正在執行");
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread mtf = new MyThread();
mtf.start();
try {
mtf.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主線程運行結束");
}
}
~~~
~~~Java
public class MyThread extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(getName() + "線程正在執行" + i + "次");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread mtf = new MyThread();
mtf.start();
try {
mtf.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 0; i < 20; i++) {
System.out.println("主線程正在運行第" + i + "次");
}
System.out.println("主線程運行結束");
}
}
~~~
>[info]使用join()方法也可能會發生InterruptedException異常,需要強制性的使用try-catch捕獲。
## 線程禮讓-yield()方法
線程禮讓是指當滿足某些條件的時候可以將當前的CPU調度讓給其他線程執行。如果某些不是很重要的線程搶占到資源但又不急于執行時,就可以將當前的CPU資源禮讓出去,交由其他線程先執行。
yield方法定義如下:

`public static void yield()`
**作用**:表示當前線程對象提示調度器自己愿意讓出CPU資源,**但是調度器可以自由忽略。**
~~~Java
public class MyThread extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++) {
if(i == 3) {
yield();
}
System.out.println(getName() + "線程正在執行" + i + "次");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread mtf = new MyThread();
mtf.start();
for(int i = 0; i < 20; i++) {
System.out.println("主線程正在運行第" + i + "次");
}
System.out.println("主線程運行結束");
}
}
~~~
**sleep()和yield()的區別**
* 都能是調用的線程放棄CPU,把運行機會給其他線程
* sleep()會給其他線程的運行機會,且不考慮優先級,但是yield()只會給同優先級或更高優先級的線程運行的機會(不一定能運行)
* 調用sleep()后,線程進入阻塞狀態,而調用yield()后進入就緒狀態(隨時等待JVM的再次調用)
## 線程優先級
所有創造的線程都是子線程,所有的子線程在啟動時都會保持同樣的優先權限。但是如果某些重要的線程希望可以優先搶占到CPU資源并且先執行,就可以通過修改線程的優先級實現。
哪個線程的優先級越高,哪個線程就有可能會先執行。
**線程優先級**:
* Java為線程類提供了10個優先級
* 優先級可以用整數1-10表示,超出范圍會拋出異常
* 主線程默認優先級為5
* 可以使用優先級常量表示優先級
| 方法或常量 | 類型 | 描述 |
| :--- | :---: | :--- |
| public static final in MAX_PRIORITY | 常量 | 最高優先級,數值為10 |
| public static final in NORM_PRIORITY | 常量 | 中等優先級,數值為5 |
| public static final in MIN_PRIORITY | 常量 | 最低優先級,數值為1 |
| public final void setPriority(int newPriority) | 普通 | 設置線程優先級 |
| public final int getPriority() | 普通 | 取得線程優先級 |
~~~java
public class MyThread extends Thread {
private String name;
public MyThread(String name) {
this.name = name;
}
@Override
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println("線程:" + name + "正在執行第" + i + "次");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//獲得主線程的優先級
//int mainPriority = Thread.currentThread().getPriority();
//System.out.println("主線程優先級為:" + mainPriority);
MyThread mtf = new MyThread("子線程1");
MyThread mts = new MyThread("子線程2");
//mtf.setPriority(10);
//使用常量設置線程優先級
mtf.setPriority(Thread.MAX_PRIORITY);
mts.setPriority(Thread.MIN_PRIORITY);
mtf.start();
mts.start();
//System.out.println("子線程1的優先級為:" + mtf.getPriority());
}
}
~~~
>[warning]優先級的設置與操作系統的環境和CPU的工作方式都是有很大的關系的。