阻塞队列原理及Java实现

目录

1.阻塞队列

1.举例:包饺子

1.通过多线程来实现

2.通过阻塞队列来实现

2.消息队列

1.解耦

2.削峰填谷

用消息队列来解决

3.异步操作

3.实现一个阻塞队列

使用循环数组

4.实现生产者和消费者模型

完整代码

5.虚假唤醒

1.概念及原因

2.解决方法

 


1.阻塞队列

阻塞队列也是一种队列,也满足队列的特性,先进先出

  • 入队元素时,判断队列是否已满,若满了就阻塞等待,等有位置在插入
  • 出队元素时,判断队列是否为空,若为空就阻塞等待,等有元素再取出

1.举例:包饺子

  • 和面 -> 大前提,只需要做一次(单例模式)
  • 擀皮 
  • 包饺子

1.通过多线程来实现

2.通过阻塞队列来实现

2.消息队列

本质上就是一个阻塞队列,在此间基础上为放入阻塞队列的消息打一个标签,消息的标签可以实现分组的作用

1.解耦

在设计程序的时候提出过一些要求,比如:高内聚,低耦合

  • 高内聚:是一种组织代码的方式,把功能强相关的代码写在一起,方便后期维护,增加代码的复用性
  • 低耦合:不要把相同的代码写的到处都是,一般通过抽象的方式把代码封装成方法,直接调用即可

良好的代码组织方式,可以有效地降低成本

举例:购物支付过程中的订单,支付以及物流

 

解决方案 

2.削峰填谷

峰与谷指的是消息的密集程度

  • 在流量高峰的时候用消息队列缓冲
  • 在流量下降后,再将消息队列积攒的消息慢慢解决

比如在上述订单中,双十一这种日子订单量会暴增,此时我们增加多台服务器去维护显然并不符合常理,因为一年就只在这一天需要这么多服务器,准备太多会增加大量成本以及耗费资源

用消息队列来解决

3.异步操作

  • 同步:请求当必须死等对方的响应
  • 异步:发出请求之后,自己去干别的事情,有响应时会接收到通知从而处理响应

3.实现一个阻塞队列

  • 实现一个普通队列,底层用到了两种数据结构,一个是链表,一个是循环数组
  • 阻塞队列就是在普通的队列基础上加入了阻塞等待的操作

使用循环数组

public class MyBlockingQueueforList {

    private volatile Node head;

    private volatile int size = 0;

    public volatile int compacty = 3;

    public class Node{
        int val;
        Node next;
    }



    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        Node prev = head;
        while (prev != null) {
            sb.append(prev.val);
            if(prev.next != null) {
                sb.append("->");
            }
            prev = prev.next;
        }
        sb.append("]");
        return sb.toString();
    }

    public MyBlockingQueueforList(int compacty) {
        this.compacty = compacty;
    }

    public MyBlockingQueueforList() {};



    public void put(int val) throws InterruptedException {
        synchronized (this) {
            if (size == compacty); {
                this.wait();
            }
            Node prev = head;
            for (int i = 0; i < size; i++) {
                prev = prev.next;
            }
            prev.val = val;
            size++;
            this.notify();
        }
    }

    public int take() throws InterruptedException {
        synchronized (this) {
            while (size == 0) {
                this.wait();
            }
            int val = head.val;
            head = head.next;
            size--;
            this.notify();
            return val;
        }
    }
}

4.实现生产者和消费者模型

完整代码

import java.util.concurrent.TimeUnit;

public class practice01 {

    private  static MyBlockingQueue queue = new MyBlockingQueue(3);
    public static void main(String[] args) throws InterruptedException {


        Thread t1 = new Thread(() -> {
            int num = 1;
            while (true) {
                System.out.println("生产了消息"+num);
                try {
                    queue.put(num);
                    num++;
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread t2 = new Thread(() -> {
            while (true) {
                try {
                    int num = queue.take();
                    System.out.println("减少了消息"+num);
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

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


    }
}

5.虚假唤醒

1.概念及原因

2.解决方法

 

最后别忘了给共享变量加volatile 

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值