Java生产消费者模式代码实现

161 阅读2分钟

1、定义

  • 生产者和消费者模式:假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
  • 如果仓库中没有产品,则生产者将产品放入仓库,如果仓库中有产品,则停止产生并等待,直到仓库中的产品消费者取走为止
  • 如果仓库中放有产品,则消费则将产品拿出仓库,如果仓库中没有产品,则停止消费并等待,直到仓库中再次放入产品为止

2、wait/nofiy实现方式```

LinkedBlockingQueue或者ArrayBlockingQueue

package com.example.cp;

import java.util.ArrayList;
import java.util.List;

public class ThreadTest01 {

    public static void main(String[] args) {
        ArrayList<Bread> list = new ArrayList<Bread>();
        Thread thread1 = new Thread(new Producer(list));
        Thread thread2 = new Thread(new Consumer(list));
        thread1.start();
        thread2.start();
    }


    static class Bread{
        private  String s;

        public Bread(String s){
             this.s = s;
         }
    }

    static class Producer implements Runnable{
        private ArrayList<Bread> list;
        public Producer(ArrayList<Bread> list){
            this.list = list;
        }
        @Override
        public void run() {
            while(true){
                synchronized (list){
                    if(list.size()>10){
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    Bread bread = new Bread("kent");
                    list.add(bread);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"生产了:"+bread.s);
                    System.out.println("生产中还剩下:"+list.size());

                    list.notify();
                }
            }
        }
    }

    static class Consumer implements Runnable{
        private ArrayList<Bread> list;
        public Consumer(ArrayList<Bread> list){
            this.list = list;
        }

        @Override
        public void run() {
            while(true){
                synchronized (list){
                    if(list.size()==0){
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    Bread remove = list.remove(0);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"消费了:"+remove.s);
                    System.out.println("消费中还剩下:"+list.size());

                    list.notify();
                }
            }
        }
    }
}

3、阻塞队列 BlockingQueue

package com.example.cp;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ThreadTest03 {
    private static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);

    public static void main(String[] args) {
        Thread producerThread = new Thread(() -> {
            int i = 0;
            while(true) {
                try {
                    queue.put(++i);
                    Thread.sleep(500);
                    System.out.println("Produced: " + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread consumerThread1 = new Thread(() -> {
            while(true) {
                try {
                    Thread.sleep(500);
                    int value = queue.take();
                    System.out.println("Consumed1: " + value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread consumerThread2 = new Thread(() -> {
            while(true) {
                try {
                    int value = queue.take();
                    Thread.sleep(1000);
                    System.out.println("Consumed2: " + value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        producerThread.start();
        consumerThread1.start();
        consumerThread2.start();
    }
}
```

LinkedBlockingQueue和ArrayBlockingQueue的区别

LinkedBlockingQueue和ArrayBlockingQueue都是Java中常用的阻塞队列,它们有以下几点不同:

  1. 实现方式:LinkedBlockingQueue是一个由链表实现的有界队列,而ArrayBlockingQueue是一个对象数组+一把锁+两个条件实现的阻塞队列。
  2. 容量限制:LinkedBlockingQueue的容量限制是可选的,如果在初始化时没有指定容量,那么默认使用int的最大值作为队列容量。而ArrayBlockingQueue必须指定大小,即容量有限。
  3. 线程安全性:LinkedBlockingQueue的内部实现添加和删除是使用两个ReentrantLock来控制并发,而ArrayBlockingQueue只使用了一个。
  4. 吞吐量:在正常情况下,LinkedBlockingQueue的吞吐效率比ArrayBlockingQueue的效率要高。
  5. 内存模型:LinkedBlockingQueue的内存模型比ArrayBlockingQueue更加灵活,可以更好地支持并发操作。
  6. 性能:在CPU缓存友好性方面,LinkedBlockingQueue比ArrayBlockingQueue更好,因为链表的节点比数组的元素更容易被CPU缓存。
  7. 适用场景:LinkedBlockingQueue适用于处理大量数据或高并发场景,而ArrayBlockingQueue适用于处理少量数据或低并发场景。

总的来说,LinkedBlockingQueue相对于ArrayBlockingQueue更加灵活、高效和适用于高并发场景,而ArrayBlockingQueue则相对简单和适用于低并发场景。