天天看點

多線程——4線程間的通信

多線程——4線程間的通信

一、内容安排

  1. wait和notify方法
  2. 簡單的生産者消費者
  3. 面試點

二、文章内容

1. wait和notify方法

​ 當一個對象調用了wait方法那麼它将阻塞目前線程, 直到有另外一個線程調用了目前對象的notify方法,被阻塞的線程才可能被喚醒。

​ 注意: 若要調用這兩個方法必須先獲得對象的鎖,不讓會抛出異常

  • 案列: 啟動A、B兩個線程,A線程中調用wait方法在wait之後列印”被喚醒“; 在B線程中先列印”我來喚醒“,然後調用notify方法
public static void main(String[] args) {
        //定義公用對象
        Object object = new Object();

        //線程A
        new Thread(()->{

            synchronized (object) {
                try {
                    //調用object的wait方法阻塞目前線程
                    object.wait();
                    //列印
                    System.out.println("我被喚醒了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //線程B
        new Thread(()->{
            System.out.println("我要喚醒A線程");
            synchronized (object) {
                try {
                    TimeUnit.SECONDS.sleep(3);
                    object.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
           

2.簡單的生産者消費者

有了上面提到的wait和notify兩個方法,我們可以利用這兩個方法實作一個簡單(生産者生産一個等待消費者消費再生産)的生産者消費者;

實作思路:

  1. 開啟兩個線程,一個不斷的生産一個不斷的消費
  2. 生産者線程生産消息之後喚醒等待中的消費者并讓自己阻塞,等待消費者消費之後讓消費者喚醒自己
  3. 消費者線程: 消費消息,喚醒生産者線程,然後自己阻塞

具體實作:

public class ProducerConsumer {

    static Object LOCK = new Object();
    static Boolean isProduced = false;
    static Integer i = 0;

    public static void main(String[] args) {

        // 定義生産者線程
        new Thread(() -> {
            while (true) {
                synchronized (LOCK) {
                    if (!isProduced) {
                        System.out.println("生産者生産消息" + ++i);
                        LOCK.notify();
                        isProduced = true;
                    } else {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "producer").start();


        // 定義消費者線程
        new Thread(() -> {
            while (true) {
                synchronized (LOCK) {
                    if (isProduced) {
                        System.out.println("消費者生産消息" + i);
                        LOCK.notify();
                        isProduced = false;
                    } else {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "consumer").start();


    }
}

           

3.面試考點

  • wait和sleep的差別
    1. 所屬對象不同: wait是Object中的方法, sleep是Thread中的方法
    2. sleep不會釋放鎖,而wait會釋放鎖
    3. sleep可以直接使用在任何地方, 但是使用wait方法必須使用在同步帶嗎塊兒中;并且需要使用鎖對象
    4. sleep自動喚醒, wait需要别人喚醒