JavaEE學習日誌持續更新----> 必看!JavaEE學習路線(文章總彙)
Java學習日誌(十二)
線程狀態
在API中 java.lang.Thread.State 這個枚舉中給出了六種線程狀態:
線程狀態 | 導致狀態發生條件 |
---|---|
NEW(新建) | 線程剛被創建,但是並未啓動。還沒調用start方法。 |
Runnable(可運行) | 線程可以在java虛擬機中運行的狀態,可能正在運行自己代碼,也可能沒有,這取決於操作系統處理器。 |
Blocked(鎖阻塞) | 當一個線程試圖獲取一個對象鎖,而該對象鎖被其他的線程持有,則該線程進入Blocked狀態;當該線程持有鎖時,該線程將變成Runnable狀態。 |
Waiting(無限等待) | 一個線程在等待另一個線程執行一個(喚醒)動作時,該線程進入Waiting狀態。進入這個狀態後是不能自動喚醒的,必須等待另一個線程調用notify或者notifyAll方法才能夠喚醒。 |
Timed Waiting(計時等待) | 同waiting狀態,有幾個方法有超時參數,調用他們將進入Timed Waiting狀態。這一狀態將一直保持到超時期滿或者接收到喚醒通知。帶有超時參數的常用方法有Thread.sleep 、 Object.wait。 |
Teminated(被 終止) | 因爲run方法正常退出而死亡,或者因爲沒有捕獲的異常終止了run方法而死亡。 |
等待與喚醒案例(包子鋪案例)
等待與喚醒:線程之間的通信
Object類中的方法
void wait()
導致當前線程等待它被喚醒,通常是通知或中斷 。void notify()
喚醒正在此對象監視器(對象鎖)上等待的單個線程。
注意:
- wait和notify方法必須由鎖對象調用(必須是同個鎖對象)
鎖對象–>wait() 鎖對象–>notify() - wait和notify方法一般寫在同步中
案例:包子鋪案例
需求:
兩大線程:設線程A(包子鋪),執行生產包子的動作。線程B(吃貨),執行吃包子的操作
共享資源:包子
執行動作:生產一個包子,吃一個包子
分析:
對包子的狀態進行分析
沒有包子:吃貨線程喚醒包子鋪線程—>吃貨線程等待—>包子鋪線程做包子—>包子鋪做好包子—>修改包子的狀態—>有包子
有包子:包子鋪喚醒吃貨線程—>包子鋪線程等待—>吃貨吃包子—>修改包子的狀態—>沒有包子
…(循環)
代碼實現:
資源類:包子,其中有皮,陷,包子的狀態
public class BaoZi {
String pi;
String xian;
//包子狀態,初始值爲false,沒有包子
boolean flag = false;
}
包子鋪類:是一個線程類,線程任務:生產包子
對包子的狀態進行判斷:
true:有包子
包子鋪線程調用wait等待
false:沒有包子
包子鋪線程生產包子
生產x皮x陷的包子
生產包子花費3秒
生產完包子,修改包子狀態爲true
包子鋪線程喚醒吃貨線程,吃包子
注意:
- 生產包子和吃包子,只能有一個在執行,需要使用同步技術
- 同步技術需要使用鎖對象,可以使用包子對象
在成員位置創建一個包子對象
使用構造方法爲包子變量賦值
public class BaoZiPu implements Runnable {
//在成員位置創建一個包子對象
BaoZi bz;
//使用構造方法爲包子變量賦值
public BaoZiPu(BaoZi bz) {
this.bz = bz;
}
//線程任務:生產包子
@Override
public void run() {
while(true){
/*
1.生產包子和吃包子,只能有一個在執行,需要使用同步技術
2.同步技術需要使用鎖對象,可以使用包子對象
*/
synchronized (bz){
//對包子狀態進行判斷
if(bz.flag==true){
//true:有包子
// 包子鋪線程調用wait等待
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//包子鋪被吃貨喚醒之後執行的代碼
//false:沒有包子,包子鋪線程生產包子
//生產x皮x陷的包子
bz.pi = "薄皮";
bz.xian = "玉米鮮肉";
System.out.println("包子鋪正在生產"+bz.pi+bz.xian+"的包子!");
//生產包子花費3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//生產完包子,修改包子狀態爲true
bz.flag = true;
//包子鋪線程喚醒吃貨線程,吃包子
bz.notify();
System.out.println("包子鋪已經生產好"+bz.pi+bz.xian+"的包子!");
}
}
}
}
吃貨類:是一個線程類,線程任務:吃包子
對包子的狀態進行判斷:
false:沒有包子
吃貨線程調用wait等待
true:有包子
吃貨線程開始吃包子
打印吃x皮x陷的包子
吃完包子,修改包子的狀態爲false
吃貨線程喚醒包子鋪線程,做包子
注意:
- 生產包子和吃包子,只能有一個在執行,需要使用同步技術
- 同步技術需要使用鎖對象,可以使用包子對象
在成員位置創建一個包子對象
使用構造方法爲包子變量賦值
public class ChiHuo implements Runnable{
//在成員位置創建一個包子對象
BaoZi bz;
//使用構造方法爲包子變量賦值
public ChiHuo(BaoZi bz) {
this.bz = bz;
}
//線程任務:吃包子
@Override
public void run() {
while (true){
/*
1.生產包子和吃包子,只能有一個在執行,需要使用同步技術
2.同步技術需要使用鎖對象,可以使用包子對象
*/
synchronized (bz){
//對包子的狀態進行判斷
// false:沒有包子
if (bz.flag==false){
//吃貨線程調用wait等待
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*
吃貨線程被包子鋪線程喚醒之後執行的代碼
*/
//true:有包子,吃貨線程開始吃包子
//打印吃x皮x陷的包子
System.out.println("吃貨正在吃"+bz.pi+bz.xian+"的包子!");
//吃完包子,修改包子的狀態爲false
bz.flag = false;
//吃貨線程喚醒包子鋪線程,做包子
bz.notify();
System.out.println("吃貨已經吃完了"+bz.pi+bz.xian+"的包子!包子鋪趕緊生產包子!");
System.out.println("-----------------------");
}
}
}
}
測試類:
創建一個包子對象
創建一個包子鋪線程,生產包子
創建一個吃貨線程,吃包子
public class Demo01 {
public static void main(String[] args) {
//創建一個包子對象
BaoZi bz = new BaoZi();
//創建一個包子鋪線程,生產包子
new Thread(new BaoZiPu(bz)).start();
//創建一個吃貨線程,吃包子
new Thread(new ChiHuo(bz)).start();
}
}
運行結果:
包子鋪正在生產薄皮玉米鮮肉的包子!
包子鋪已經生產好薄皮玉米鮮肉的包子!
吃貨正在吃薄皮玉米鮮肉的包子!
吃貨已經吃完了薄皮玉米鮮肉的包子!包子鋪趕緊生產包子!
-----------------------
包子鋪正在生產薄皮玉米鮮肉的包子!
包子鋪已經生產好薄皮玉米鮮肉的包子!
吃貨正在吃薄皮玉米鮮肉的包子!
吃貨已經吃完了薄皮玉米鮮肉的包子!包子鋪趕緊生產包子!
-----------------------
...