線程通信面試題:【等待和喚醒】

題目要求:

請用“等待喚醒”機制編寫一個程序,要求:

第一個線程:遍歷1--1000所有的數字,在遍歷過程中,如果發現這個數字能同時被2,3,5,7整除,立即wait()退出等待,讓第二個線程進入。

第二個線程:運行後,將一個計數器 + 1,之後再喚醒等待的線程。     

主線程中:休息2秒,讓兩個線程全部執行完畢,打印“計數器”的結果。

這題主要出的是線程通信的問題。但要注意鎖對象是在線程中傳遞,它的屬性值可以發生變化。而基本類型不能做爲鎖,它的包裝類如果做爲鎖的話,值不能發生變化,不然鎖會失。所以定義了一個類做爲鎖對象,鎖對象可以修改它的屬性值,因爲鎖本身的引用沒有變化。

答案:

package com.itheima.day13.essential;

/**
 * @author by NewBoy
 * @since 2020/3/4
 */
public class Demo31WaitNotify {

    public static void main(String[] args) {
        //創建鎖對象
        Lock lock = new Lock();

        WaitThread t1 = new WaitThread(lock);
        t1.start();

        NotifyThread t2 = new NotifyThread(lock);
        t2.start();


        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("計數器結果是:" + t2.count);
    }

}

/**
 * 鎖對象,在線程中傳遞,但它的屬性值可以發生變化
 * 而基本類型不能做爲鎖,它的包裝類如果做爲鎖的話,值不能發生變化,不然鎖會失效
 * 所以定義了一個類做爲鎖對象,鎖對象可以修改它的屬性值,因爲鎖本身的引用沒有變化
 */
class Lock {
    //標記:是否需要喚醒
    boolean needNofity = false;
}

/**
 * 第一個線程:遍歷1--1000所有的數字,在遍歷過程中,如果發現這個數字能同時被
 * 2,3,5,7整除,立即wait()退出等待,讓第二個線程進入。
 */
class WaitThread extends Thread {

    private Lock lock;

    public WaitThread(Lock lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            for (int i = 1; i <= 1000; i++) {
                if (i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 == 0) {
                    try {
                        System.out.println(i + "=> 進入等待狀態");
                        //設置標記告訴另一個線程我需要喚醒,另一個線程如果通知就加1,否則不加
                        lock.needNofity = true;
                        //等待自己
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //喚醒別人
                lock.notify();
            }
        }
    }
}

/**
 * 第二個線程:運行後,將一個計數器 + 1,之後再喚醒等待的線程。
 */
class NotifyThread extends Thread {
    private Lock lock;

    public NotifyThread(Lock lock) {
        this.lock = lock;
    }

    //計數器
    public int count = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                //判斷是否需要喚醒
                if (lock.needNofity) {
                    //喚醒
                    lock.notify();
                    //計數器加1
                    System.out.println("喚醒" + (++count) + "次");
                    //將喚醒的標記設置爲false
                    lock.needNofity = false;
                }
                try {
                    //自己等待
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

運行結果:

210=> 進入等待狀態
喚醒1次
420=> 進入等待狀態
喚醒2次
630=> 進入等待狀態
喚醒3次
840=> 進入等待狀態
喚醒4次

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章