多线程设计模式(2)—— 生产者消费者模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/AnselLyy/article/details/80960616

欢迎访问 我的个人博客

  • 也叫缓存绑定问题(bounded- buffer),是一个经典的、多进程同步问题
  • 分为 1. 单生产者和单消费者 和 2. 多生产者和多消费者 两种

单生产者和单消费者

有两个进程:一组生产者进程和一组消费者进程共享一个初始为空、固定大小为n的缓存(缓冲区)。
生产者的工作是制造一段数据,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待,如此反复;
同时,只有缓冲区不空时,消费者才能从中取出消息,一次消费一段数据(即将其从缓存中移出),否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息。

关键点

  • 要保证不让生产者在缓存还是满的时候仍然要向内写数据
  • 不让消费者试图从空的缓存中取出数据

描述

在生产者-消费者模式中,通常有两类线程,即若干个生产者线程和若干个消费者线程。
生产者线程负责提交用户请求,消费者线程负责处理用户请求。生产者和消费者之间通过共享内存缓冲区进行通信。生产者-消费者模式中的内存缓冲区的主要功能是数据在多线程间的共享。
此外,通过该缓冲区,可以缓解生产者和消费者之间的性能差。

案例

通过馒头和篮子的案例进行示范

馒头(实体类)

class ManTou {

    int id;

    public ManTou(int id) {
        // TODO Auto-generated constructor stub
        this.id = id;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "馒头: " + id;
    }

}

篮子(实体类 | 共享的数据池)

class SyncBasket {

    int index = 0;
    ManTou[] basket = new ManTou[6];

    // 放馒头
    public synchronized void push(ManTou manTou) {

        while (index == basket.length) {
            try {

                // 如果篮子已经满了,那就将该线程放入等锁池中,等待篮子中的馒头被消费
                this.wait();
            } catch (InterruptedException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }

        this.notifyAll();
        basket[index++] = manTou;
        System.out.println("生产了: " + manTou);

    }

    // 取馒头
    public synchronized ManTou pop() {

        while (index == 0) {
            try {

                // 如果篮子为空的,那就将该线程放入等锁池中,直到有新的馒头放入篮子中
                this.wait();
            } catch (InterruptedException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }

        this.notifyAll();
        System.out.println("消费了: " + basket[--index]);

        return basket[index];
    }

}

生产者(Producer)

class Producer implements Runnable {

    private SyncBasket sync;

    public Producer(SyncBasket syncBasket) {
        // TODO Auto-generated constructor stub
        this.sync = syncBasket;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        for (int i = 0; i < 20; i++) {
            ManTou manTou = new ManTou(i);
            sync.push(manTou);

//          try {               
//          // 沉睡一秒
//              Thread.sleep(1000);
//              
//          } catch (InterruptedException e) {
//              // TODO: handle exception
//              e.printStackTrace();
//          }
        }

    }

}

消费者(Consumer)

class Consumer implements Runnable {

    private SyncBasket sync;

    public Consumer(SyncBasket syncBasket) {
        // TODO Auto-generated constructor stub

        this.sync = syncBasket;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        for (int i  = 0; i < 20; i++) {
            sync.pop();         
        }

    }

}

Test

public class ProducerAndConsumer {

    public static void main(String[] args) {

        SyncBasket syncBasket = new SyncBasket();

        Producer producer = new Producer(syncBasket);
        Thread t1 = new Thread(producer);

        Consumer consumer = new Consumer(syncBasket);
        Thread t2 = new Thread(consumer);

        t1.start();
        t2.start();

    }

}

猜你喜欢

转载自blog.csdn.net/AnselLyy/article/details/80960616