1、sleep 與 yield
sleep
-
調用 sleep 會讓當前線程從 Running 進入 Timed Waiting 狀態(阻塞)
-
其它線程可以使用 interrupt 方法打斷正在睡眠的線程,這時 sleep 方法會拋出
InterruptedException
-
睡眠結束後的線程未必會立刻得到執行
-
建議用 TimeUnit 的 sleep 代替 Thread 的 sleep 來獲得更好的可讀性(TimeUnit.SECONDS.sleep(1);)
調用sleep
public static void main(String[] args) {
Thread t1 = new Thread("t1") {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t1.start();
log.debug("t1 state: {}", t1.getState());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("t1 state: {}", t1.getState());
}
輸出
22:23:02.365 c.Test6 [main] - t1 state: RUNNABLE
22:23:02.893 c.Test6 [main] - t1 state: TIMED_WAITING
調用interrupt
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("enter sleep...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
log.debug("wake up...");
e.printStackTrace();
}
}
};
t1.start();
Thread.sleep(1000);
log.debug("interrupt...");
t1.interrupt();
}
輸出
22:26:48.155 c.Test7 [t1] - enter sleep...
22:26:49.158 c.Test7 [main] - interrupt...
22:26:49.158 c.Test7 [t1] - wake up...
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at cn.itcast.test.Test7$1.run(Test7.java:14)
yield
-
調用 yield 會讓當前線程從 Running 進入 Runnable 就緒狀態,然後調度執行其它線程,注意:如果沒有其他線程的話,可能還是執行當前線程
-
具體的實現依賴於操作系統的任務調度器
2、sleep yield區別
共同點:
1.都是Thread類中的類方法
2.都會導致正在執行的線程釋放CPU
區別:
1.線程進入的狀態不同:sleep方法導致線程進入到阻塞狀態,yield方法導致線程進入就緒狀態
2.是否考慮線程優先級:sleep方法不會考慮線程優先級,當一個線程調用sleep方法釋放CPU後,所有優先級級別的線程都有機會獲得CPU。yield方法會考慮線程優先級。當一個線程調用sleep方法釋放CPU後,與該線程具有同等優先級,或優先級比該線程高的線程有機會獲得CPU
3.可移植性:sleep方法比yield方法具有更好的可移植性
4.是否拋出異常:sleep方法聲明拋出InterruptedException,而yield方法沒有聲明任何異常
5.是否有參數:sleep方法在Thread類中有兩種重載形式,sleep(long ms),sleep(long ms,int nanos)yield方法沒有參數
3、線程優先級
-
線程優先級會提示(hint)調度器優先調度該線程,但它僅僅是一個提示,調度器可以忽略它
-
如果 cpu 比較忙,那麼優先級高的線程會獲得更多的時間片,但 cpu 閒時,優先級幾乎沒作用
所以不一定優先級設置高就一定能有限執行,具體執行依賴任務調度器。
Runnable task1 = () -> {
int count = 0;
for (;;) {
System.out.println("---->1 " + count++);
}
};
Runnable task2 = () -> {
int count = 0;
for (;;) {
// Thread.yield();
System.out.println(" ---->2 " + count++);
}
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t2");
// t1.setPriority(Thread.MIN_PRIORITY);
// t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
這裏讀者可將註釋去掉自行實踐,即可體會yield與優先級的使用。