深入Thread.sleep
友情推薦:
實戰分析
一直都說,Threed.sleep是不會釋放鎖,而wait是釋放鎖的(物件鎖),現理論上來分析一下啊。
由於CPU分配的每個執行緒的時間片極為短暫(一般為幾十毫秒),所以,CPU通過不停地切換執行緒執行,這樣就給程式設計師一種錯覺,以為多個執行緒是在同時執行。sleep就是正在執行的執行緒主動讓出CPU,CPU去執行其他執行緒,在sleep指定的時間過後,CPU才會回到這個執行緒上繼續往下執行,如果當前執行緒進入了同步鎖,sleep方法並不會釋放鎖,即使當前執行緒使用sleep方法讓出了CPU,但其他被同步鎖擋住了的執行緒也無法得到執行。
package thread.concurrent;
public class DeepenSleep implements Runnable {
private int number = 10;
public void firstMethod() throws Exception {
synchronized (this) {
System. out.println("in first method");
number += 100;
System. out.println("+100=" + number);
}
}
public void secondMethod() throws Exception {
synchronized (this) {
System. out.println("in second method, prepare sleep");
/**
* (休息2S,阻塞執行緒) 以驗證當前執行緒物件的機鎖被佔用時, 是否被可以訪問其他同步程式碼塊
*/
Thread. sleep(2000 );
System. out.println("wake up!!");
// this.wait(2000);
number *= 200;
System. out.println("*200=" + number);
}
}
@Override
public void run() {
try {
System. out.println("run thread...");
firstMethod();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
DeepenSleep dt = new DeepenSleep();
Thread thread = new Thread(dt);
thread.start();
System. out.println("prepare run second method");
dt.secondMethod();
}
}
輸出如下:
分析:主執行緒啟動起來,因為建立執行緒等的資源消耗,所以主執行緒會先執行 dt.secondMethod(),因此會先輸出prepare run second method,其後執行secondMehtod方法(注意該方法是要先鬧到鎖物件),而該方法直接將執行緒睡眠2s(注意此處物件鎖DeepenSleep的例項物件並沒有釋放),然後執行執行緒dt的run方法,該方剛發執行dt的firstMethod,然而,該方法也是需要獲取鎖物件的,而此時他沒先不能獲取到,因為secondMehtod沒有釋放鎖(準確點講,主執行緒沒有釋放鎖);然後等了2s,主執行緒睡眠時間已過,他warkup之後,因為還擁有鎖,因此直接run secondMethod的剩下的方法,先輸出”wake up”,然後執行 number*200,執行完,主執行緒釋放掉鎖,而dt執行緒拿到鎖,執行run方法,拿到鎖,執行run方法的synchronized的剩餘方法:先輸出”in first method”,然後執行加100的操作。
我們來變一下將firstMethod的同步去掉,看輸出是什麼樣子
package thread.concurrent;
public class DeepenSleep implements Runnable {
private int number = 10;
public void firstMethod() throws Exception {
// synchronized (this) {
System. out.println( "in first method");
number += 100;
System. out.println( "+100=" + number);
// }
}
public void secondMethod() throws Exception {
synchronized ( this) {
System. out.println( "in second method, prepare sleep");
/**
* (休息2S,阻塞執行緒) 以驗證當前執行緒物件的機鎖被佔用時, 是否被可以訪問其他同步程式碼塊
*/
Thread. sleep(2000);
System. out.println( "wake up!!");
// this.wait(2000);
number *= 200;
System. out.println( "*200=" + number);
}
}
@Override
public void run() {
try {
System. out.println( "run thread...");
firstMethod();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
DeepenSleep dt = new DeepenSleep();
Thread thread = new Thread(dt);
thread.start();
System. out.println( "prepare run second method");
dt.secondMethod();
}
}
輸出如下:
分析:不同點在於,主執行緒睡眠之後,沒有釋放鎖,dt執行緒執行firstMethod並不需要鎖,因此先run firstMethod中的邏輯,先加100,然今,主執行緒睡醒之後,再執行剩下的邏輯,乘以200。
Thread.sleep(1000),1000ms後是否立即執行?
不一定,在未來的1000毫秒內,執行緒不想再參與到CPU競爭。那麼1000毫秒過去之後,這時候也許另外一個執行緒正在使用CPU,那麼這時候作業系統是不會重新分配CPU的,直到那個執行緒掛起或結束;況且,即使這個時候恰巧輪到作業系統進行CPU 分配,那麼當前執行緒也不一定就是總優先順序最高的那個,CPU還是可能被其他執行緒搶佔去。
Thread.sleep(0),是否有用?
boss:“給你睡0小時”。
coder:“你TM逗我啊”。
休眠0ms,這樣的休眠有何意義?Thread.Sleep(0)的作用,就是“觸發作業系統立刻重新進行一次CPU競爭,重新計算優先順序”。競爭的結果也許是當前執行緒仍然獲得CPU控制權,也許會換成別的執行緒獲得CPU控制權。這也是我們在大迴圈裡面經常會寫一句Thread.sleep(0) ,因為這樣就給了其他執行緒比如Paint執行緒獲得CPU控制權的權力,這樣介面就不會假死在那裡。
微信掃我^_^