線程讓步: yield()
yield()的作用是讓步。它能讓當前線程由“運行狀態”進入到“就緒狀態”,從而讓它具有相同優先級的等待線程獲取執行權;但是,並不能保證在當前線程調用yield()之後,其它具有相同優先權的執行緒一定能獲得執行權;也有可能是當前執行緒又進入到「運行狀態」繼續運行!
範例:
class ThreadA extends Thread{ public ThreadA(String name){ super(name); } public synchronized void run(){ for(int i=0; i <10; i++){ System.out.printf("%s [%d]:%d\n", this.getName(), this.getPriority(), i); // i整除4时,调用yield if (i%4 == 0) Thread.yield(); } } } public class YieldTest{ public static void main(String[] args){ ThreadA t1 = new ThreadA("t1"); ThreadA t2 = new ThreadA("t2"); t1.start(); t2.start(); } }
(某一次的)運行結果:
t1 [5]:0 t2 [5]:0 t1 [5]:1 t1 [5]:2 t1 [5]:3 t1 [5]:4 t1 [5]:5 t1 [5]:6 t1 [5]:7 t1 [5]:8 t1 [5]:9 t2 [5]:1 t2 [5]:2 t2 [5]:3 t2 [5]:4 t2 [5]:5 t2 [5]:6 t2 [5]:7 t2 [5]:8 t2 [5]:9
結果說明:
「執行緒t1」在能被4整數的時候,並沒有切換到「執行緒t2」。這表明,yield()雖然可以讓線程由“運行狀態”進入到“就緒狀態”;但是,它不一定會讓其它線程獲取CPU執行權(即,其它線程進入到“運行狀態”),即使這個「其它執行緒」與目前呼叫yield()的執行緒具有相同的優先權。
yield() 與 wait()的比較:
我們知道,wait()的作用是讓當前執行緒由「運作狀態」進入「等待(阻塞)狀態」的同時,也會釋放同步鎖定。而yield()的作用是讓步,它也會讓目前執行緒離開「運行狀態」。它們的區別是:
(1) wait()是讓線程由“運行狀態”進入到“等待(阻塞)狀態”,而不yield()是讓線程由“運行狀態”進入到“就緒狀態”。
(2) wait()是會執行緒釋放它所持有物件的同步鎖,而yield()方法不會釋放鎖定。
下面透過範例示範yield()是不會釋放鎖的:
public class YieldLockTest{ private static Object obj = new Object(); public static void main(String[] args){ ThreadA t1 = new ThreadA("t1"); ThreadA t2 = new ThreadA("t2"); t1.start(); t2.start(); } static class ThreadA extends Thread{ public ThreadA(String name){ super(name); } public void run(){ // 获取obj对象的同步锁 synchronized (obj) { for(int i=0; i <10; i++){ System.out.printf("%s [%d]:%d\n", this.getName(), this.getPriority(), i); // i整除4时,调用yield if (i%4 == 0) Thread.yield(); } } } } }
(某一次)運行結果:
t1 [5]:0 t1 [5]:1 t1 [5]:2 t1 [5]:3 t1 [5]:4 t1 [5]:5 t1 [5]:6 t1 [5]:7 t1 [5]:8 t1 [5]:9 t2 [5]:0 t2 [5]:1 t2 [5]:2 t2 [5]:3 t2 [5]:4 t2 [5]:5 t2 [5]:6 t2 [5]:7 t2 [5]:8 t2 [5]:9
結果說明:
主執行緒main中啟動了兩個執行緒t1和t2。 t1和t2在run()會引用同一個物件的同步鎖,即synchronized(obj)。在t1運行過程中,雖然它會呼叫Thread.yield();但是,t2是不會取得cpu執行權的。因為,t1並沒有釋放「obj所持有的同步鎖」!
執行緒休眠:sleep()
sleep() 定義在Thread.java。
sleep() 的作用是讓目前執行緒休眠,也就是目前執行緒會從「運行狀態」進入到「休眠(阻塞)狀態」。 sleep()會指定休眠時間,執行緒休眠的時間會大於/等於該休眠時間;當執行緒重新喚醒時,它會由“阻塞狀態”變成“就緒狀態”,從而等待cpu的調度執行。
範例:
class ThreadA extends Thread{ public ThreadA(String name){ super(name); } public synchronized void run() { try { for(int i=0; i <10; i++){ System.out.printf("%s: %d\n", this.getName(), i); // i能被4整除时,休眠100毫秒 if (i%4 == 0) Thread.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } } } public class SleepTest{ public static void main(String[] args){ ThreadA t1 = new ThreadA("t1"); t1.start(); } }
運行結果:
t1: 0 t1: 1 t1: 2 t1: 3 t1: 4 t1: 5 t1: 6 t1: 7 t1: 8 t1: 9
結果說明:
程式比較簡單,在主執行緒main啟動執行緒t1。 t1啟動之後,當t1中的計算i能被4整除時,t1會透過Thread.sleep(100)休眠100毫秒。
sleep() 與 wait()的比較:
我們知道,wait()的作用是讓當前執行緒由「運作狀態」進入「等待(阻塞)狀態」的同時,也會釋放同步鎖定。而sleep()的作用是也是讓目前執行緒由「運行狀態」進入到「休眠(阻塞)狀態」。
但是,wait()會釋放物件的同步鎖定,而sleep()則不會釋放鎖定。
下面透過範例示範sleep()是不會釋放鎖定的。
public class SleepLockTest{ private static Object obj = new Object(); public static void main(String[] args){ ThreadA t1 = new ThreadA("t1"); ThreadA t2 = new ThreadA("t2"); t1.start(); t2.start(); } static class ThreadA extends Thread{ public ThreadA(String name){ super(name); } public void run(){ // 获取obj对象的同步锁 synchronized (obj) { try { for(int i=0; i <10; i++){ System.out.printf("%s: %d\n", this.getName(), i); // i能被4整除时,休眠100毫秒 if (i%4 == 0) Thread.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } } } } }
運行結果:
t1: 0 t1: 1 t1: 2 t1: 3 t1: 4 t1: 5 t1: 6 t1: 7 t1: 8 t1: 9 t2: 0 t2: 1 t2: 2 t2: 3 t2: 4 t2: 5 t2: 6 t2: 7 t2: 8 t2: 9
結果說明:
主執行緒main啟動了兩個執行緒t1和t2。 t1和t2在run()會引用同一個物件的同步鎖,即synchronized(obj)。在t1運行過程中,雖然它會呼叫Thread.sleep(100);但是,t2是不會取得cpu執行權的。因為,t1並沒有釋放「obj所持有的同步鎖」!
注意,若我們註解掉synchronized (obj)後再次執行該程序,t1和t2是可以互相切換的。以下是註釋調synchronized(obj) 之後的源碼:
public class SleepLockTest{ private static Object obj = new Object(); public static void main(String[] args){ ThreadA t1 = new ThreadA("t1"); ThreadA t2 = new ThreadA("t2"); t1.start(); t2.start(); } static class ThreadA extends Thread{ public ThreadA(String name){ super(name); } public void run(){ // 获取obj对象的同步锁 // synchronized (obj) { try { for(int i=0; i <10; i++){ System.out.printf("%s: %d\n", this.getName(), i); // i能被4整除时,休眠100毫秒 if (i%4 == 0) Thread.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } // } } } }
更多詳解Java中的線程讓步yield()與線程休眠sleep()方法相關文章請關注PHP中文網!