Java-線程等待、喚醒與中斷


一、sleep() 與 wait()

兩者都會讓當前線程進入等待狀態。喚醒后都需要等待 CPU 資源,不一定會立即執行。若在等待期間被調用此線程的的 interrupt() 方法,將會產生 InterruptedException 異常。

wait() 是 Object 類的方法,會釋放對象鎖,並讓出 CPU 資源。只能在 synchronized 下使用,使用 notify() 或 notiftAll() 喚醒。

// 線程工廠,這里主要用來設置線程名字
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
// 創建線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(6, 6, 0L,
        TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(1024),
        namedThreadFactory,
        new ThreadPoolExecutor.AbortPolicy());

Object object = new Object();
threadPool.execute(() -> {
    try {
        synchronized (object) {
            object.wait();
            System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAA");
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

threadPool.execute(() -> {
    synchronized (object) {
        System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBBB");
        object.notify();
    }
});
View Code

sleep() 是 Thread 類的靜態方法,只會讓出 CPU 資源。可以使低優先級的線程得到執行的機會。

// 線程工廠,這里主要用來設置線程名字
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
// 創建線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(6, 6, 0L,
        TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(1024),
        namedThreadFactory,
        new ThreadPoolExecutor.AbortPolicy());

threadPool.execute(() -> {
    try {
        // 阻塞 1 秒
        Thread.sleep(1000);
        System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

threadPool.execute(() -> {
    System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBBBB");
});
View Code

兩個示例都保證了 B 會在 A 之前被打印

  

二、notify() 與 notifyAll()

與 wait() 配合使用。兩者都會喚醒其他線程,且會釋放對象鎖,不會阻塞當前線程。

其中 notify() 只喚醒等待線程當中的一個,notifyAll() 會喚醒所有等待線程。

notify() 是隨機喚醒的,不同的 JDK 版本,在等待隊列中喚醒的線程,其位置在等待隊列中不同。

JDK1.8 中 notify() 喚醒的是等待隊列中的頭節點,即等待時間最長的那個線程。

喚醒的線程為同一個對象鎖的線程。喚醒一個或所有,都只有一個線程會獲取到鎖對象。

 

三、yield() 與 join()

yield() 是 Thread 類的靜態原生 (native) 方法,作用是讓出 CPU 資源,不會阻塞當前線程,但可能讓出 CPU 資源后,系統重新調度后又會選擇給該線程 CPU 資源。使用場景比較少。

join() 是Thread 類實例的方法,可以使得一個線程在另一個線程結束后再執行。當前運行的線程將進入到等待狀態直到另一個線程執行完成。

Thread t1 = new Thread(){
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("A");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

Thread t2 = new Thread(){
    @Override
    public void run() {
        try {
            t1.join();
            System.out.println("B");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

t2.start();
t1.start();
View Code

示例中保證了 A 在 B 之前被打印

 

四、interrupt()

中斷等待狀態的線程,並拋出異常。相關方法有三個。

interrupt() 是 Thread 類實例的方法,給線程中斷狀態設置為 false,等線程進入到等待狀態時就會被中斷,並拋出異常

isInterrupted() 是 Thread 類實例的方法,檢測線程的中斷狀態

interrupted() 是 Thread 類的靜態方法,實質調用的是 currentThread().isInterrupted(true),作用是檢測線程的中斷狀態,然后將狀態設置為 true

Thread t1 = new Thread() {
    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + "啟動后的中斷狀態:" + Thread.currentThread().isInterrupted());

            Thread.currentThread().interrupt();
            System.out.println(Thread.currentThread().getName() + "interrupt()后的中斷狀態:" + Thread.currentThread().isInterrupted());

            System.out.println(Thread.currentThread().getName() + "isInterrupted()獲取中斷狀態:" + Thread.interrupted());
            System.out.println(Thread.currentThread().getName() + "interrupted()后的中斷狀態:" + Thread.currentThread().isInterrupted());

            Thread.currentThread().interrupt();
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println(Thread.currentThread().getName() + "異常時中斷狀態:" + Thread.interrupted());
        }
    }
};

new Thread() {
    @Override
    public void run() {
        System.out.println(t1.getName() + "未啟動時的中斷狀態:" + t1.isInterrupted());
        System.out.println("=======================================================");
        t1.start();
        try {
            t1.join();
            System.out.println("=======================================================");
            System.out.println(t1.getName() + "執行完時的中斷狀態:" + t1.isInterrupted());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}.start();
View Code


https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM