本文是線程篇的一個分支,主要結合個人理解,看一下sleep和wait以及線程的一些狀態
網上的圖看起來都有點醜,我本身畫了一幅:bash
1.New: 新建態: new Thread ~ thread.start期間
2.Runnable: 可執行態: 可被CPU調度執行期間。
3.Running 運行態: 線程獲取CPU權限進行執行
4.Blocked 阻塞狀態: 阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。
|---等待阻塞:經過調用線程的wait()方法,讓線程等待某工做的完成。
|---同步阻塞:線程在獲取synchronized同步鎖失敗(由於鎖被其它線程所佔用)時
|---其餘阻塞:經過調用線程的sleep()或join()或發出了I/O請求時
5.Dead 死亡狀態: 線程執行完了或者因異常退出了run()方法,該線程結束生命週期。
複製代碼
暫停當前線程,進入Blocked狀態,把cpu片斷讓出給其餘線程。ide
public class Main0 {
static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
public static void main(String[] args) {
new Thread(new Car()).start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Ambulance()).start();
}
private static class Car implements Runnable {
@Override
public void run() {
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動,在路上跑");
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車跑到終點");
}
}
private static class Ambulance implements Runnable {
@Override
public void run() {
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車開始啓動,在路上跑");
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車跑到終點");
}
}
}
複製代碼
02:29表明當前時刻的分秒,即2分29秒
---->[運行結果]----------------------
02:29:小汽車開始啓動,在路上跑
02:29:小汽車跑到終點
02:31:救護車開始啓動,在路上跑
02:31:救護車跑到終點
複製代碼
private static class Car implements Runnable {
@Override
public void run() {
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動,在路上跑");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車跑到終點");
}
}
複製代碼
Car線程的任務是睡5s,可見主線程的休眠沒有影響到Car子線程的運行(休眠)post
18:48:小汽車開始啓動,在路上跑
18:50:救護車開始啓動,在路上跑
18:50:救護車跑到終點
18:53:小汽車跑到終點
複製代碼
在線程1中加synchronized(
這裏鎖用sdf對象,你也能夠任意
)測試
public class Main2 {
static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
public static void main(String[] args) {
new Thread(new Car()).start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Ambulance()).start();
}
private static class Car implements Runnable {
@Override
public void run() {
synchronized (sdf){
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動,在路上跑");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車跑到終點");
}
}
}
private static class Ambulance implements Runnable {
@Override
public void run() {
synchronized (sdf){
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車開始啓動,在路上跑");
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車跑到終點");
}
}
}
}
複製代碼
Car線程和Ambulance線程在運行時使用同一把鎖,線程在休眠時不會釋放鎖
因此Ambulance線程須要等待Car線程執行完成,才能進行執行ui
23:46:小汽車開始啓動,在路上跑
23:51:小汽車跑到終點
23:51:救護車開始啓動,在路上跑
23:51:救護車跑到終點
複製代碼
Object#wait()
方法的做用在
線程t1
調用A對象
的wait()方法
,會釋放t1持有的鎖
,讓t1進入等待隊列(Blocked狀態)
直到其餘線程調用A對象的notify()方法
或notifyAll()
方法t1進入同步隊列(Blocked狀態)
當t1得到鎖後會進入就緒狀態Runnable
,獲取CPU的調度權後會繼續執行,再貼一遍這個圖:spa
既然是釋放當前線程的鎖,那麼不須有鎖才行,並且必須用該鎖的對象調用wait方法
好比上面是用sdf對象加鎖的,必須使用sdf.wait();
,不然會拋出InterruptedException
線程
private static class Car implements Runnable {
@Override
public void run() {
synchronized (sdf) {
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動,在路上跑");
try {
Thread.sleep(3000);//模擬執行3s的任務以後
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車緊急剎車....");
sdf.wait();
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動....");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車跑到終點");
}
}
}
private static class Ambulance implements Runnable {
@Override
public void run() {
synchronized (sdf) {
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車開始啓動,在路上跑");
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車跑到終點");
}
}
}
複製代碼
在Car線程調用
sdf.wait();
後,鎖將被釋放,而後Ambulance線程就能夠持有鎖運行了
若是不喚醒線程,線程將一直阻塞,就是根本停不下來
。打個比方就是sdf是司機
wait()
以後就把車鑰匙扔了,而後熄火了。鑰匙拿不回來,車就跑不了。須要notify()
獲取車鑰匙3d
30:48:小汽車開始啓動,在路上跑
30:51:小汽車緊急剎車....
30:51:救護車開始啓動,在路上跑
30:51:救護車跑到終點
而後就阻塞在這裏停不下來了....
複製代碼
注意wait和notify須要使用同一個對象,不然然並卵
在Ambulance線程跑完後喚醒Car線程,而後Car獲取所後會進入就緒態code
private static class Ambulance implements Runnable {
@Override
public void run() {
synchronized (sdf) {
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車開始啓動,在路上跑");
System.out.println(sdf.format(System.currentTimeMillis()) + ":救護車跑到終點");
sdf.notify();
}
}
}
複製代碼
40:23:小汽車開始啓動,在路上跑
40:26:小汽車緊急剎車....
40:26:救護車開始啓動,在路上跑
40:26:救護車跑到終點
40:26:救護車:喂,哥們,醒醒,你能夠開了...
40:26:小汽車開始啓動....
40:31:小汽車跑到終點
複製代碼
Thread#join()
方法 和Thread#yield
public class Main6 {
static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
public static void main(String[] args) {
Thread car = new Thread(new Car());
car.start();
System.out.println(sdf.format(System.currentTimeMillis()) + ":main線程結束");
}
private static class Car implements Runnable {
@Override
public void run() {
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動,在路上跑");
try {
Thread.sleep(3000);//模擬執行3s的任務以後
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車跑到終點");
}
}
}
複製代碼
26:28:小汽車開始啓動,在路上跑
26:28:main線程結束
26:31:小汽車跑到終點
複製代碼
阻塞當前線程,知道join的線程結束或超時orm
public class Main6 {
static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
public static void main(String[] args) {
Thread car = new Thread(new Car());
car.start();
try {
car.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sdf.format(System.currentTimeMillis()) + ":main線程結束");
}
private static class Car implements Runnable {
@Override
public void run() {
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車開始啓動,在路上跑");
try {
Thread.sleep(3000);//模擬執行3s的任務以後
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽車跑到終點");
}
}
}
---->[打印結果]-----------------------------
31:53:小汽車開始啓動,在路上跑
31:56:小汽車跑到終點
31:56:main線程結束
複製代碼
讓出線程的cpu調度權,以後再一塊兒搶奪。
運行狀態-->就緒狀態
public class Main7 {
public static void main(String[] args) {
Thread car = new Car("car");
Thread ambulance = new Car("Ambulance");
car.start();
ambulance.start();
}
private static class Car extends Thread {
public Car(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "----" + i);
if (i == 5) {
yield();
}
}
}
}
}
複製代碼
運行了幾組數據,大部分知足讓出調度權後,另外一個線程執行,也有少許狀況不是。
因此yield說明我如今不急,能夠劃劃水,執行權可讓出去。不過接下來誰執行仍是不定的。
1.關於synchronized鎖這裏不展開,不瞭解的能夠見:線程篇3:[-synchronized-]
2.關於synchronized鎖對象須要一致,不然鎖不住,然並卵。經常使用class對象,如Car.class
3.能夠設置超時喚醒xxx.wait(3000)
,即3s後喚醒線程。
4.能夠設置join超時xxx.join(3000)
,即3s後線程進入就緒態。
5.notifyAll:來着黑暗寒冬的隨從們,僕人們,士兵們,遵從克爾蘇加德的召喚吧!
item | 從屬 | 是否釋放鎖 | 狀態轉變爲 | 異常 |
---|---|---|---|---|
sleep | Thread 靜態方法 | NO | 阻塞 | InterruptedException |
wait | Object 公共方法 | YES | 等待隊列 | IllegalMonitorStateException+InterruptedException |
notify/notifyAll | Object 公共方法 | -- | 同步隊列 | IllegalMonitorStateException |
join | Thread 公共方法 | NO | 阻塞 | InterruptedException |
yield | Thread 公共方法 | NO | 可執行態 | 無 |