生产者消费者模型设计

生产者消费者模型设计

生产者消费者模型设计必须满足以下几点

  1. 生产者和消费者共享一个消息队列, 且所有线程在对共享队列进行操作的时候都必须加锁
  2. 生产者在队列满的时候不能再生产,必须阻塞自己
  3. 消费者在队列空的时候不能再消费,必须阻塞自己
  4. 共享队列从无到有的时候必须唤醒阻塞的消费者
  5. 共享队列从满到不满的时候必须唤醒阻塞的生产者
1. 首先建造一个产品类
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Product  {
    private String name;
}
2. 建造一个生产者类,为了实现多线程场景下的生产,需要实现Runnable接口, 重写run方法
import java.util.Queue;
import java.util.Random;

public class Producer implements Runnable{
    private Queue<Product> queue;
    private int maxCapacity;
    public Producer(Queue queue, int maxCapacity) {
        this.queue = queue;
        this.maxCapacity = maxCapacity;
    }
    @Override
    public void run() {
        synchronized (queue) {
            // 必须用while, 因为当线程唤醒之后, 有可能还处于队列满的状态, 此时不能继续向下执行, 必须再次进行判断
            while (queue.size() == maxCapacity) {
                try {
                    System.out.println("生产者" + Thread.currentThread().getName() + "等待中... Queue 已达到最大容量,无法生产");
                    queue.wait(); // wait 释放锁
                    System.out.println("生产者" + Thread.currentThread().getName() + "退出等待");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //队列里的产品从无到有,需要通知在等待的消费者
            if (queue.size() == 0) queue.notifyAll();
            Integer productId = new Random().nextInt();
            queue.offer(new Product("产品"  + productId));
            System.out.println(Thread.currentThread().getName() + "--------生产了产品:" + productId);
        }
    }
}
3. 建造一个消费者类,为了实现多线程场景下的生产,需要实现Runnable接口, 重写run方法
import java.util.Queue;

public class Consumer implements Runnable{
    private Queue<Product> queue;
    private int maxCapacity;
    public Consumer(Queue queue, int maxCapacity) {
        this.queue = queue;
        this.maxCapacity = maxCapacity;
    }
    @Override
    public void run() {
        synchronized (queue) {
            // 必须用while, 因为当线程唤醒之后, 有可能还处于队列空的状态, 此时不能继续向下执行, 必须再次进行判断
            while (queue.isEmpty()) {
                try {
                    System.out.println(Thread.currentThread().getName() + "等待中... Queue 已缺货,无法消费");
                    queue.wait();
                    System.out.println(Thread.currentThread().getName() + "退出等待");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (queue.size() == maxCapacity) queue.notifyAll();
            Product product = queue.poll();
            System.out.println(Thread.currentThread().getName() + "--------消费了:" + product.getName());
        }
    }
}

4.模拟100个线程进行生产,100个线程进行消费,生产者和消费者共享一个队列,所以所有的线程在对队列进行操作的时候都必须加锁
import java.util.ArrayDeque;
import java.util.Queue;

public class Test {
    public static void main(String[] args) {

        // 生产者消费者共享的是同一个 queue
        Queue<Product> queue = new ArrayDeque<>();

        for (int i = 0; i < 100; i++) {
            new Thread(new Producer(queue, 100), "生产者" + (i + 1)).start();
            new Thread(new Consumer(queue, 100), "消费者" + (i + 1)).start();
        }

    }
}

你可能感兴趣的:(java,中间件,数据库)