阻塞队列和生产者消费者模型

简介: 阻塞队列是一种特殊队列,当队列空时,获取元素操作会被阻塞;当队列满时,插入操作会被阻塞。可通过数组模拟实现,使用`wait`和`notify`控制阻塞与唤醒。生产者消费者模型中,阻塞队列作为缓冲区,实现生产者与消费者的解耦,提高系统可维护性和扩展性。

1. 阻塞队列

1.1. 阻塞队列的使用

阻塞队列是一种特殊的队列,相比于普通的队列,它支持两个额外的操作:当队列为空时,获取元素的操作会被阻塞,直到队列中有元素可用;当队列已满时,插入元素的操作会被阻塞,直到队列中有空间可以插入新元素。

当阻塞队列满的时候,线程就会进入阻塞状态:

public class ThreadDemo19 {
    public static void main(String[] args) throws InterruptedException {
        BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>(3);
        blockingDeque.put(1);
        System.out.println("添加成功");
        blockingDeque.put(2);
        System.out.println("添加成功");
        blockingDeque.put(3);
        System.out.println("添加成功");
        blockingDeque.put(4);
        System.out.println("添加成功");
    }
}

同时,当阻塞队列中没有元素时,再想要往外出队,线程也会进入阻塞状态

public class ThreadDemo20 {
    public static void main(String[] args) throws InterruptedException {
        BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>(20);
        blockingDeque.put(1);
        System.out.println("添加成功");
        blockingDeque.put(2);
        System.out.println("添加成功");
        blockingDeque.take();
        System.out.println("take成功");
        blockingDeque.take();
        System.out.println("take成功");
        blockingDeque.take();
        System.out.println("take成功");
    }
}

1.2. 实现阻塞队列

根据阻塞队列的特性,可以尝试来自己手动实现一下

可以采用数组来模拟实现:

public class MyBlockingDeque {
    private String[] data = null;
    private int head = 0;
    private int tail = 0;
    private int size = 0;
    public MyBlockingDeque(int capacity) {
        data = new String[capacity];
    }
}

接下来是入队列的操作:

public void put(String s) throws InterruptedException {
    synchronized (this) {
        while (size == data.length) {
            this.wait();
        }
        data[tail] = s;
        tail++;
        if (tail >= data.length) {
            tail = 0;
        }
        size++;
        this.notify();
    }
}

由于设计到变量的修改,所以要加上锁,这里调用wait和notify来模拟阻塞场景,并且需要注意wait要使用while循环,如果说被Interrupted打断了,那么就会出现不可预料的错误

出队列也是相同的道理:

public String take() throws InterruptedException {
String ret = "";
synchronized (this) {
    while (size == 0) {
        this.wait();
    }
    ret = data[head];
    head++;
    if (head >= data.length) {
        head = 0;
    }
    size--;
    this.notify();
}
return ret;
}

2. 生产者消费者模型

生产者消费者模型是一种经典的多线程同步模型,用于解决生产者和消费者之间的协作问题。在这个模型中,生产者负责生产数据并将其放入缓冲区,消费者负责从缓冲区中取出数据并进行处理。生产者和消费者之间通过缓冲区进行通信,彼此之间不需要直接交互。这样可以降低生产者和消费者之间的耦合度,提高系统的可维护性和可扩展性。

而阻塞队列可以当做上面的缓冲区:

public class ThreadDemo21 {
    public static void main(String[] args) {
        BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>(100);
        Thread t1 = new Thread(()->{
            int i = 1;
            while (true){
                try {
                    blockingDeque.put(i);
                    System.out.println("生产元素:" + i);
                    i++;
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t2 = new Thread(()->{
            while (true){
                try {
                    int i = blockingDeque.take();
                    System.out.println("消费元素:" + i);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();
        t2.start();
    }
}

如果说把sleep的操作放到线程2会怎么样?

线程一瞬间就把阻塞队列沾满了,后面还是一个线程生产,一个线程消费,虽然打印出来的有偏差

相关文章
|
3月前
|
存储 设计模式 安全
使用BlockingQueue实现生产者-消费者模式
使用BlockingQueue实现生产者-消费者模式
|
5月前
|
监控 安全 Java
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
|
5月前
|
消息中间件 安全 Java
多线程(初阶七:阻塞队列和生产者消费者模型)
多线程(初阶七:阻塞队列和生产者消费者模型)
48 0
|
5月前
|
C++
C++11实现生产者消费者
C++11实现生产者消费者
70 1
|
5月前
线程同步之 生产者消费者模型详解
前言 博主本来没打算讲这个比较前面的知识的(博主socket编程还有两个部分没讲,进程也才写完回收僵尸进程的三种方法,信号捕捉器也才完结),但是今天有朋友来问博主,什么是生产者消费者模型,所以博主就先为为数不多的朋友把生产者消费者模型讲一讲,希望大家能看懂(没有现成和锁知识的朋友不要急,这部分是写给有基础的朋友看的,这些知识博主都会慢慢的讲到)。 前言 博主本来没打算讲这个比较前面的知识的(博主socket编程还有两个部分没讲,进程也才写完回收僵尸进程的三种方法,信号捕捉器也才完结),但是今天有朋友来问博主,什么是生产者消费者模型,所以博主就先为为数不多的朋友把生产
44 0
|
Linux
Linux线程的生产者消费者模型 --- 阻塞队列(blockqueue)(二)
Linux线程的生产者消费者模型 --- 阻塞队列(blockqueue)(二)
88 0
|
缓存 Linux 数据安全/隐私保护
Linux线程的生产者消费者模型 --- 阻塞队列(blockqueue)(一)
Linux线程的生产者消费者模型 --- 阻塞队列(blockqueue)(一)
106 0
|
存储
生产者消费者模型(二)
生产者消费者模型
68 0
|
存储 数据处理 容器
生产者消费者模型(一)
生产者消费者模型
136 0