Java線(xiàn)程中wait、await、sleep、yield、join用法總結(jié)

一、wait()、notify()、notifyAll()用法

obj.wait()/obj.wait(long timeout)是Object中的方法,當(dāng)線(xiàn)程調(diào)用wait()方法,當(dāng)前線(xiàn)程釋放對(duì)象鎖,進(jìn)入等待隊(duì)列。

obj.notify()/obj.nogifyAll()是Object中的方法,喚醒在此對(duì)象上wait()的單個(gè)或者所有線(xiàn)程。

測(cè)試代碼:

public class ThreadWaitNotify {

    public static void main(String[] args) throws InterruptedException {
        //創(chuàng)建一個(gè)線(xiàn)程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        //創(chuàng)建DemoTest對(duì)象
        DemoTest demoTest = new DemoTest();
        //用線(xiàn)程池創(chuàng)建線(xiàn)程異步執(zhí)行waitTest方法
        executorService.submit(() -> demoTest.waitTest());
        //用線(xiàn)程池創(chuàng)建線(xiàn)程異步執(zhí)行notifyTest方法
        executorService.submit(() -> demoTest.notifyTest());
    }

    //測(cè)試wait和notify測(cè)試demo
    static class DemoTest {
        //喚醒線(xiàn)程
        public synchronized void notifyTest() {
            System.out.println("方法notifyTest開(kāi)始執(zhí)行了");
            notify();
            System.out.println("方法notifyTest執(zhí)行結(jié)束了");
        }
        //執(zhí)行wait操作將線(xiàn)程掛起,注意必須結(jié)合synchronized使用
        public synchronized void waitTest() {
            System.out.println("方法waitTest開(kāi)始執(zhí)行了");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("方法waitTest執(zhí)行結(jié)束了");
        }
    }
}

打印日志:

方法waitTest開(kāi)始執(zhí)行了
方法notifyTest開(kāi)始執(zhí)行了
方法notifyTest執(zhí)行結(jié)束了
方法waitTest執(zhí)行結(jié)束了

從日志中我們可以看出waitTest方法阻塞直到被notifyTest喚醒

二、await()、signal()、signalAll()用法

java.util.concurrent類(lèi)庫(kù)中提供的Condition類(lèi)來(lái)實(shí)現(xiàn)線(xiàn)程之間的協(xié)調(diào)。

condition.await()/condition.await(long time, TimeUnit unit):通過(guò)condition調(diào)用,當(dāng)前線(xiàn)程釋放對(duì)象鎖。

condition.signal()/condition.signalAll():通過(guò)signal或者signalAll方法喚醒a(bǔ)wait掛起的線(xiàn)程。

測(cè)試代碼:

public class ThreadAwaitSignal {
    public static void main(String[] args) {
        //創(chuàng)建一個(gè)線(xiàn)程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        //創(chuàng)建DemoTest對(duì)象
        DemoTest demoTest = new DemoTest();
        //用線(xiàn)程池創(chuàng)建線(xiàn)程異步執(zhí)行awaitTest方法
        executorService.submit(() -> demoTest.awaitTest());
        //用線(xiàn)程池創(chuàng)建線(xiàn)程異步執(zhí)行signalTest方法
        executorService.submit(() -> demoTest.signalTest());
    }

    /**
     * 使用java.util.conncurrent類(lèi)中提供了Condition類(lèi)來(lái)實(shí)現(xiàn)線(xiàn)程之間的協(xié)調(diào)
     * 可以在Condition上調(diào)用await()方法使線(xiàn)程掛起
     * 其他線(xiàn)程調(diào)用signal()或者signalAll()來(lái)喚醒線(xiàn)程
     */
    static class DemoTest {
        //定義一個(gè)Lock對(duì)象用來(lái)獲取Condition對(duì)象
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        //喚醒線(xiàn)程
        public void signalTest() {
            lock.lock();
            try {
                System.out.println("方法signalTest開(kāi)始執(zhí)行了");
                condition.signalAll();
                System.out.println("方法signalTest執(zhí)行結(jié)束了");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        //結(jié)合lock鎖實(shí)現(xiàn)Condition的await
        public void awaitTest() {
            lock.lock();
            try {
                System.out.println("方法awaitTest開(kāi)始執(zhí)行了");
                condition.await();
                System.out.println("方法awaitTest執(zhí)行結(jié)束了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

打印日志:

方法awaitTest開(kāi)始執(zhí)行了
方法signalTest開(kāi)始執(zhí)行了
方法signalTest執(zhí)行結(jié)束了
方法awaitTest執(zhí)行結(jié)束了

從日志中國(guó)可以看出我們得到了和wait同樣的效果。

三 、yield()、join()用法

Thread.yield():一定是當(dāng)前線(xiàn)程調(diào)用此方法,當(dāng)前線(xiàn)程放棄獲取CPU的時(shí)間片,由運(yùn)行態(tài)轉(zhuǎn)變?yōu)榫途w態(tài),讓操作系統(tǒng)中再次選擇線(xiàn)程執(zhí)行。作用:讓相同優(yōu)先級(jí)的線(xiàn)程輪流執(zhí)行,但并不能保證輪流執(zhí)行,根據(jù)解釋我們了解到,轉(zhuǎn)成就緒態(tài)的的線(xiàn)程還有可能再次選中執(zhí)行。Thread.yield()方法不會(huì)導(dǎo)致阻塞。

t.join()/t.join(long millis):當(dāng)前線(xiàn)程調(diào)用t2.join()方法,當(dāng)前線(xiàn)程阻塞但是不會(huì)釋放對(duì)象鎖,直到t2線(xiàn)程執(zhí)行完畢或者millis時(shí)間到,則當(dāng)前的線(xiàn)程恢復(fù)就緒狀態(tài)。作用:讓優(yōu)先級(jí)比較高的線(xiàn)程優(yōu)先執(zhí)行。

yield測(cè)試代碼:

    //yield放棄CPU時(shí)間片
    public static void yieldTest(){
        //定義一個(gè)線(xiàn)程
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + ": 測(cè)試線(xiàn)程開(kāi)始執(zhí)行。。。");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ": 測(cè)試線(xiàn)程執(zhí)行結(jié)束了。");
        });
        thread.start();
        System.out.println(Thread.currentThread().getName() + ": 執(zhí)行yield方法");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + ": 主線(xiàn)程開(kāi)始執(zhí)行");
    }

打印結(jié)果:

main: 執(zhí)行yield方法
main: 主線(xiàn)程開(kāi)始執(zhí)行
Thread-0: 測(cè)試線(xiàn)程開(kāi)始執(zhí)行。。。
Thread-0: 測(cè)試線(xiàn)程執(zhí)行結(jié)束了。

可以看出雖然主線(xiàn)程調(diào)用了yield,但是仍然又開(kāi)始執(zhí)行了,因此但并不能保證輪流執(zhí)行。

join測(cè)試代碼:

   //join搶占CPU時(shí)間片
    public static void joinTest() throws InterruptedException {
        //定義一個(gè)線(xiàn)程
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + ": 測(cè)試線(xiàn)程開(kāi)始執(zhí)行。。。");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ": 測(cè)試線(xiàn)程執(zhí)行結(jié)束了。");
        });
        thread.start();
        System.out.println(thread.getName() + ": 執(zhí)行join方法");
        thread.join();
        System.out.println(Thread.currentThread().getName() + ": 主線(xiàn)程開(kāi)始執(zhí)行");
    }

打印日志:

Thread-0: 執(zhí)行join方法
Thread-0: 測(cè)試線(xiàn)程開(kāi)始執(zhí)行。。。
Thread-0: 測(cè)試線(xiàn)程執(zhí)行結(jié)束了。
main: 主線(xiàn)程開(kāi)始執(zhí)行

從日志中我們可以看出主線(xiàn)程在線(xiàn)程執(zhí)行完成后才開(kāi)始執(zhí)行。

四、wait()、await()、sleep()、yield、join對(duì)比

通過(guò)表格對(duì)比(join的情況下,t1指代當(dāng)前線(xiàn)程,t2代表其他線(xiàn)程)


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容