JAVA多线程之生产消费模型

时间:2021-08-09
本文章向大家介绍JAVA多线程之生产消费模型,主要包括JAVA多线程之生产消费模型使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

生产消费模型

所谓生产消费模型,是通过一个容器来解决生产者和消费者的强耦合问题。通俗的讲,就是生产者不断的生产,
消费之也在不断消费,消费者消费的产品是生产者生产的,这就必然存在一个中间的容器,我们可以把这个容器
想象成一个仓库,当仓库没有满的时候,生产者生产产品,当仓库满了的时候,生产者不能继续生产产品,而需
处于等待状态。当仓库不为空的时候,消费者可以消费产品,当仓库为空的时候,消费者不能再消费产品,而应
处于等待状态。这样不断循环,在这个过程中,生产者和消费者是不直接杰出的,所谓的仓库其实就是一个阻塞
队列,生产者生产的产品不直接提供给消费者,而是提供给阻塞队列,这个阻塞队列就是来解决生产者和消费者
之间的强耦合,这就是生产者消费者模型。

wait()方法

1、注意wait()是Object里面的方法,而不是Thread里面的。它的作用是将当前线程置于预执行队列,并在wait()
所在的代码处停止,等待唤醒通知。
2、wait()只能在同步代码块或同步方法中执行,如果调用wait()方法,而没有持有适当的锁,就会抛出异常。
wait()方法调用后会释放出锁,线程与其他线程竞争重新获取锁。
3、线程调用了wait()方法后一直在等待,不会继续往下执行,wait()一旦执行,除非接受到唤醒操作或者异常
中断,否则不会往下执行

notify()方法

1、notify()方法也是要在同步代码块或者同步方法中调用的,它的作用是使停止的线程继续执行,调用notify()
方法后,会通知那些等待当前线程对象锁的线程,并使它们重新获取该线程的对象锁,如果等待线程比较多的时候,
则由线程规划器随机挑选出一个呈现wait状态的线程。
2、notify()调用之后不会立即释放锁,而是当执行notify()的线程执行完成,即退出同步代码块或同步方法时,
才会释放对象锁。

notifyAll()

唤醒所有处于等待状态的线程,一般使用notifyAll()比较多,因为notify随机唤醒一个线程,可能不是我们想要的
造成程序出现问题,notifyAll()唤醒所有等待线程则一定会得到我们想要的

例程

测试1,不加入同步和线程通信

Test类

package com.lding.test2;

public class Test {
    public static void main(String[] args) {
        Queue queue=new Queue();
        new Thread(new Producer(queue)).start();
        new Thread(new Consumer(queue)).start();
    }
}

Queue类

package com.lding.test2;

public class Queue {
    private int n;

    public int getN() {
        System.out.println("消费:"+n);
        return n;
    }

    public void setN(int n) {
        System.out.println("生产:"+n);
        this.n = n;
    }
}

Producer类

package com.lding.test2;

public class Producer implements Runnable{
    Queue queue;
    Producer(Queue queue){
        this.queue=queue;
    }
    @Override
    public void run() {
        int i=0;
        while (true){
            queue.setN(i++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Consumer类

package com.lding.test2;

public class Consumer implements Runnable{
    Queue queue;
    Consumer(Queue queue){
        this.queue=queue;
    }
    @Override
    public void run() {
        while (true){
            queue.getN();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果

可以看到,0生产了一次却消费了两次。

测试2 加上同步

Queue类

package com.lding.test2;

public class Queue {
    private int n;

    public synchronized int getN() {
        System.out.println("消费:"+n);
        return n;
    }

    public synchronized void setN(int n) {
        System.out.println("生产:"+n);
        this.n = n;
    }
}


生产了18并没有消费
生产了22消费了两次22

版本3 加上线程之间的通信

Queue类

package com.lding.test2;

public class Queue {
    private int n;
    boolean flag=false;//flag=false 容器中无数据, flag=true 容器中有商品
    public synchronized int getN() {
        if(!flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费:"+n);
        flag=false;//消费完毕 容器没数据
        notifyAll();
        return n;
    }

    public synchronized void setN(int n) {
        if(flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("生产:"+n);
        this.n = n;
        flag=true;//生产完毕 容器中有数据
        notifyAll();
    }
}

运行结果完全是生产一个,消费一个,不会出现生产一次消费两次或者生产完不消费的情况。

你以为的极限,也许只是别人的起点

原文地址:https://www.cnblogs.com/LengDing/p/15118084.html