生产者消费者案例,使用wait和notify进行线程间的数据通信

生产者消费者案例,使用wait和notify进行线程间的数据通信

之前学习了线程同步的只是,接下来学习一下线程间的通信相关的知识,这里简单来一个生产者消费者的案例来作为入门,实现效果需为生产者生产一个数字,消费者消费一个数字,代码如下:

public class ProduceConsumerVersion1 {
    private int i = 1;
    private final Object LOCK = new Object();

    private void produce() {
        synchronized (LOCK) {
            System.out.println("P->" + (i++));
        }
    }

    private void consume() {
        synchronized (LOCK) {
            System.out.println("C->" + (i));
        }
    }

    public static void main(String[] args) {
        ProduceConsumerVersion1 pc = new ProduceConsumerVersion1();

        new Thread(() -> {
            while (true) {
                pc.produce();
            }
        }, "P").start();
        new Thread(() -> {
            while (true) {
                pc.consume();
            }
        }, "C").start();
    }

第一版使用两个线程,一个生产者一个消费者,他们使用同一个锁,也就是不存在两个线程同时执行的情况,++的执行次数是不可控的,我们猜测并不是生产一个消费一个,代码运行效果如下:

这时候想实现,不停的生产不停的消费同时还要生产一个消费一个,就需要线程间的通信了,第一版因为没有线程之间的通信协作,对于生产者来说它不知道有人消费了,而对于消费者来说它也不知道有人生产了,接下来我们改进代码:

public class ProduceConsumerVersion2 {
    private int i = 0;
    private final Object LOCK = new Object();
    /**
     * 是否已经消费
     */
    private volatile boolean isProduced = false;

    public void produce() {
        synchronized (LOCK) {
            if (isProduced) {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("P->" + (++i));
                LOCK.notify();
                isProduced = true;
            }
        }
    }

    public void consume() {
        synchronized (LOCK) {
            if (isProduced) {
                System.out.println("C->" + i);
                LOCK.notify();
                isProduced = false;
            } else {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        ProduceConsumerVersion2 pc = new ProduceConsumerVersion2();
        // 单个生产者、消费者运行程序
        new Thread(() -> {
            while (true) {
                pc.produce();
            }
        }, "P").start();

        new Thread(() -> {
            while (true) {
                pc.consume();
            }
        }, "C").start();
    }
}

运行效果如下:

可以看到已经做到我们想要的效果了,生产正不断的生产,消费者不断地消费,每次生产一个消费一个,但是实际上当有多个生产者消费者的时候还是会有问题的,这个后面再说,先总结一下wait和notify。

**wait: **调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回,需要注意的

是调用 wait()方法后,会释放对象的锁。因此,wait 方法一般用在同步方法或同步代码块中。

notify: Object 类中的 notify() 方法,唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象

上等待,则会选择唤醒其中一个线程,选择是任意的,并在对实现做出决定时发生,线程通过调

用其中一个 wait() 方法,在对象的监视器上等待,直到当前的线程放弃此对象上的锁定,才能继

续执行被唤醒的线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞

争。类似的方法还有 notifyAll() ,唤醒再次监视器上等待的所有线程。

posted @ 2020-09-06 18:43  风暴松鼠  阅读(196)  评论(0)    收藏  举报