Java 多執行緒基礎(七)執行緒休眠 sleep

Java 多執行緒基礎(七)執行緒休眠 sleep

一、執行緒休眠 sleep

sleep() 方法定義在Thread.java中,是 static 修飾的靜態方法。
sleep() 的作用是讓當前執行緒休眠,即當前執行緒會從「運行狀態」進入到「休眠(阻塞)狀態」。sleep()會指定休眠時間,執行緒休眠的時間會大於/等於該休眠時間;在執行緒重新被喚醒時,它會由「阻塞狀態」變成「就緒狀態」,從而等待cpu的調度執行。

二、sleep示例

public class SleepTest {
    private static Object obj = new Object();
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");
        t1.start();
    }
    
    static class MyThread extends Thread{
        public MyThread(String name) {
            super(name);
        }
        public void run() {
            synchronized (obj) {
                try {
                    for(int i = 0;i < 5;i++) {
                        System.out.println(Thread.currentThread().getName() + "--" + i);
                        if (i % 4 == 0)
                            Thread.sleep(1000);// i能被4整除時,休眠1秒
                    }
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
// 運行結果
t1--0  
t1--1
t1--2
t1--3
t1--4

說明:

在主執行緒main中啟動執行緒t1。t1啟動之後,當t1中的計算i能被4整除時,t1會通過Thread.sleep(100)休眠100毫秒。

三、sleep(long millis) 與 wait(long timeout)

我們知道,wait()的作用是讓當前執行緒由「運行狀態」進入「等待(阻塞)狀態」的同時,也會釋放同步鎖。而sleep()的作用是也是讓當前執行緒由「運行狀態」進入到「休眠(阻塞)狀態」。
但是,wait() 會釋放對象的同步鎖,而 sleep() 則不會釋放鎖

通過下面的程式碼,演示 sleep() 不會釋放鎖的:

public class SleepTest {
    private static Object obj = new Object();
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");
        Thread t2 = new MyThread("t2");
        t1.start();
        t2.start();
    }
    
    static class MyThread extends Thread{
        public MyThread(String name) {
            super(name);
        }
        public void run() {
            synchronized (obj) {
                try {
                    for(int i = 0;i < 5;i++) {
                        System.out.println(Thread.currentThread().getName() + "--" + i);
               Thread.sleep(1000);// 休眠1秒 } }catch(Exception e) { e.printStackTrace(); } } } } }
// 執行結果
t1--0
t1--1
t1--2
t1--3
t1--4
t2--0
t2--1
t2--2
t2--3
t2--4

說明:

主執行緒main中啟動了兩個執行緒t1和t2。t1和t2在run()會引用同一個對象的同步鎖,即synchronized(obj)。在t1運行過程中,雖然它會調用Thread.sleep(1000) 進入休眠狀態;但是,t2是不會獲取CPU執行權的。因為,t1並沒有釋放「obj所持有的同步鎖」!
注意,若我們注釋掉 synchronized (obj) 後再次執行該程式,t1和t2是可以相互切換執行的,原因是:在沒有同步鎖的情況下,當一個執行緒進入「休眠(阻塞)狀態「時,會放棄CPU的執行權,另一個執行緒就會獲取CPU執行權。

通過下面的程式碼,演示 wait() 會釋放鎖的:

public class SleepTest {
    private static Object obj = new Object();
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");
        Thread t2 = new MyThread("t2");
        t1.start();
        t2.start();
    }
    
    static class MyThread extends Thread{
        public MyThread(String name) {
            super(name);
        }
        public void run() {
            synchronized (obj) {
                try {
                    for(int i = 0;i < 5;i++) {
                        System.out.println(Thread.currentThread().getName() + "--" + i);
                        obj.wait(1000);// 等待1秒
                    }
                }catch(Exception e) {
                    e.printStackTrace();
                }
                
            }
        }
    }
}
// 執行結果
t1--0
t2--0
t1--1
t2--1
t2--2
t1--2
t2--3
t1--3
t2--4
t1--4

說明:

主執行緒main中啟動了兩個執行緒t1和t2。t1和t2在run()會引用同一個對象的同步鎖,即synchronized(obj)。在t1運行過程中,調用 obj.wait(1000) 進入等待狀態,釋放同步鎖;此時,t2會獲取CPU執行權的。