欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

经典案例:生产者和消费者

程序员文章站 2022-05-05 16:41:50
...

经典案例:生产者和消费者


一、什么是生产者和消费者?

生产者与消费者问题是多线程同步的一个经典问题。生产者和消费者同时使用一块缓冲区,生产者生产商品放入缓冲区,消费者从缓冲区中取出商品。我们需要保证的是,当缓冲区满时,生产者不可生产商品;当缓冲区为空时,消费者不可取出商品。
经典案例:生产者和消费者

二、如何解决一个生产者与消费者问题

主要三种解决方式:

  1. wait()与notify()方法

  2. Lock与Condition机制

  3. BlockingQueue阻塞队列

1.wait()与notify()方法

wait()方法使用条件:
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。

  1. 当生产产品数量满时,调用wait()方法,使得生产者释放锁,当前线程阻塞,消费者线程可以获得锁。
  2. 当产品数量为空时,调用wait()方法,使得消费者释放锁,当前线程阻塞,生产者线程可以获得锁。

notify()方法使用条件:
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。

  1. 如果刚执行的是消费者,那么产品数量为0,就执行wait()方法等待。那么在执行生产者时,只要生产一个产品就会通过notify()方法唤醒消费者,让消费者来消费产品。
  2. 如果生产者生产产品过快,消费者来不及消费,并且到达产品上限。那么生产者就执行wait()方法等待。在消费者消费一个产品就会通过notify()方法唤醒生产者,让生产者生产产品。

代码如下:

//调度类
public class Clerk {
    //共享资源 产品数量
    private static int productCount = 0;
    //生产产品
    //必须加上同步方法,不然两个线程会产生线程安全问题
    public synchronized void produceProduct(){
        if (productCount < 20){
            productCount++;
            System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品");
            //唤醒等待的消费者
            notify();
        }else {
            //等待
            try {
                //产品数量满了,进入等待
                wait();
                System.out.println("生产满了奥,我要休息一下");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //消费产品
    public synchronized void consumeProduct(){
        if (productCount > 0){
            System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品");
            productCount--;
            //唤醒等待的生产者
            notify();
        }else {
            try {
                //产品数量为空,进入等待
                wait();
                System.out.println("商品没了奥,我要休息一下");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//生产者
public class Producer extends Thread {
    private Clerk clerk;
    public Producer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + ":开始生产产品.....");
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.produceProduct();
        }
    }
}
//消费者
public class Consumer extends Thread {
    private Clerk clerk;
    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + ":开始消费产品.....");
        while (true){
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumeProduct();
        }
    }
}
//测试类 模拟两个生产者,两个消费者
public class Test {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        
        Producer p1 = new Producer(clerk);
        p1.setName("生产者1");
        Producer p2 = new Producer(clerk);
        p2.setName("生产者2");

        Consumer c1 = new Consumer(clerk);
        c1.setName("消费者1");
        Consumer c2 = new Consumer(clerk);
        c2.setName("消费者2");
        
        p1.start();
        p2.start();
        c1.start();
        c2.start();
    }
}

运行结果如下:
经典案例:生产者和消费者