一.阻塞队列介绍

1.1阻塞队列特性

阻塞队列特性:

一.安全性

二.产生阻塞效果

阻塞队列是一种特殊的队列. 也遵守 “先进先出” 的原则.阻塞队列能是一种线程安全的数据结构, 并且具有以下特性:

  • 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素.
  • 当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素.

阻塞队列的一个典型应用场景就是 “生产者消费者模型”. 这是一种非常典型的开发模型.

1.2阻塞队列的优点

我们可以将阻塞队列比做成"生产者"和"消费者"的"交易平台".

我们可以把这个模型来比做成"包饺子"

A 的作用是擀饺子皮,也就是"生产者"

B 的作用是包饺子,也就是"消费者"

X 的作用一个当作放擀好饺子皮的一个盘中,也就是阻塞队列

这样我们根据A,B,X可以想象以下场景

场景一:

当A擀饺子皮的速度过快,X被A的杆好饺子皮放满了,这样A就需要停止擀饺子皮这一个操作,这时只能等待B来利用A提供的饺子皮包饺子后X所空出的空间,来给A提供生产的环境

场景二:

当B包饺子的速度过快,X被B的包饺子所用的饺子皮用空,这样B就需要停止包饺子这一个操作,这时只能等待A提供的饺子皮包饺子后X所存在饺子皮,来给B提供消费的环境

二.生产者消费者模型

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题

生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取

(1) 阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力.

比如在 “秒杀” 场景下, 服务器同一时刻可能会收到大量的支付请求. 如果直接处理这些支付请求,服务器可能扛不住(每个支付请求的处理都需要比较复杂的流程). 这个时候就可以把这些请求都放到一个阻塞队列中, 然后再由消费者线程慢慢的来处理每个支付请求.这样做可以有效进行 “削峰”, 防止服务器被突然到来的一波请求直接冲垮.

(2) 阻塞队列也能使生产者和消费者之间 解耦.

比如过年一家人一起包饺子. 一般都是有明确分工, 比如一个人负责擀饺子皮, 其他人负责包. 擀饺子皮的人就是 “生产者”, 包饺子的人就是 “消费者”.擀饺子皮的人不关心包饺子的人是谁(能包就行, 无论是手工包, 借助工具, 还是机器包), 包饺子的人也不关心擀饺子皮的人是谁(有饺子皮就行, 无论是用擀面杖擀的, 还是拿罐头瓶擀, 还是直接从超市买的).

2.1阻塞队列对生产者的优化

优化一:能够让多个服务器程序之间更充分的解耦合:

如果不使用生产者和消费者模型,此时A和B的耦合性比较强,如果A线程出现一些状况B就会挂,B线程出现一些状况A就会挂,这时当我们引入阻塞队列后我们就可以将A,B线程分开,如果A,B线程挂了有阻塞队列的存在下,是不会影响别的线程

优化二:能够对于请求进行"削峰填谷":

我们可以联想到我国的三峡大坝,三峡大坝就相当于阻塞队列,当我们遇到雨水大的季节,我们就可以关闭三峡大坝,利用三峡大坝来存水;当我们遇到干旱期,我们就可以打开三峡大坝的门,来放水解决干旱问题

三.标准库中的阻塞队列

3.1Java提供阻塞队列实现的标准类

java官方也提供了阻塞队列的标准类,主要有下面几个:

标准类 说明
ArrayBlockingQueue 一个由数组结构组成的有界阻塞队列
LinkedBlockingQueue 一个由链表结构组成的有界阻塞队列
PriorityBlockingQueue 一个支持优先级排序的无界阻塞队列
DelayQueue 一个使用优先级队列实现的无界阻塞队列
SynchronousQueue 一个不存储元素的阻塞队列
LinkedTransferQueue 一个由链表结构组成的无界阻塞队列
LinkedBlockingDeque 一个由链表结构组成的双向阻塞队列
BlockingQueue接口 单向阻塞队列实现了该接口
BlockingDeque接口 双向阻塞队列实现了该接口

3.2Blockingqueue基本使用

在 Java 标准库中内置了阻塞队列. 如果我们需要在一些程序中使用阻塞队列, 直接使用标准库中的即可.

BlockingQueue 是一个接口. 真正实现的类是 LinkedBlockingQueue.

put 方法用于阻塞式的入队列, take 用于阻塞式的出队列.

BlockingQueue 也有 offer, poll, peek 等方法, 但是这些方法不带有阻塞特性.

BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// 入队列
queue.put("abc");
// 出队列. 如果没有 put 直接 take, 就会阻塞.
String elem = queue.take();

四.阻塞队列实现

4.1阻塞队列的代码实现

我们通过 “循环队列” 的方式来实现

使用 synchronized 进行加锁控制.put 插入元素的时候, 判定如果队列满了, 就进行 wait. (注意, 要在循环中进行 wait. 被唤醒时不一定队列就不满了, 因为同时可能是唤醒了多个线程).take 取出元素的时候, 判定如果队列为空, 就进行 wait. (也是循环 wait)

我们在设计阻塞队列的时候可以将队列联想成一个圆

class BlockingQueue{
    //队列里存放的个数
   volatile private int size = 0;
    //队列的头节点
    private int head = 0;
    //队列的尾节点
    private int prov = 0;
    //创建一个数组,我们来给这个数组的容量设置为100
    private int[] array = new int[100];
    //创建一个专业的锁对象
    private Object object = new Object();
    //实现阻塞队列中的put方法
    public void put(int value) throws InterruptedException {
        synchronized (object) {
            //当数组已经满了
            if (size == array.length) {
                object.wait();
            } else {
                //我们可以优化成prov = (prov   1) % items.length
                array[prov] = value;
                prov   ;
               if (prov >= array.length) {
                   prov = 0;
               }
            }
            size  ;
            object.notify();
        }
    }
    //实现阻塞队列中的take方法
    public int take() throws InterruptedException {
        synchronized (object) {
            if (size == 0) {
                object.wait();
            }
            int x = array[head];
            head  ;
            if (head >= array.length) {
                head = 0;
            }
            size--;
            object.notify();
            return x;
        }
    }
}

4.2阻塞队列搭配生产者与消费者的代码实现

class BlockingQueue{
    //队列里存放的个数
   volatile private int size = 0;
    //队列的头节点
    private int head = 0;
    //队列的尾节点
    private int prov = 0;
    //创建一个数组,我们来给这个数组的容量设置为100
    private int[] array = new int[100];
    //创建一个专业的锁对象
    private Object object = new Object();
    //实现阻塞队列中的put方法
    public void put(int value) throws InterruptedException {
        synchronized (object) {
            //当数组已经满了
            if (size == array.length) {
                object.wait();
            } else {
                //我们可以优化成prov = (prov   1) % items.length
                array[prov] = value;
                prov   ;
               if (prov >= array.length) {
                   prov = 0;
               }
            }
            size  ;
            object.notify();
        }
    }
    //实现阻塞队列中的take方法
    public int take() throws InterruptedException {
        synchronized (object) {
            if (size == 0) {
                object.wait();
            }
            int x = array[head];
            head  ;
            if (head >= array.length) {
                head = 0;
            }
            size--;
            object.notify();
            return x;
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BlockingQueue blockingQueue = new BlockingQueue();
        Thread thread1 = new Thread(()-> {
            while (true) {
                for (int i = 0; i < 100; i  ) {
                    try {
                        blockingQueue.put(i);
                        System.out.println("生产了" i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread thread2 = new Thread(()->{
                while (true) {
                    try {
                        int b = blockingQueue.take();
                        System.out.println("消耗了" b);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        });
        thread1.start();
        thread2.start();
    }
}

以上就是Java多线程案例之阻塞队列详解的详细内容,更多关于Java多线程阻塞队列的资料请关注Devmax其它相关文章!

Java多线程案例之阻塞队列详解的更多相关文章

  1. iOS:核心图像和多线程应用程序

    我试图以最有效的方式运行一些核心图像过滤器.试图避免内存警告和崩溃,这是我在渲染大图像时得到的.我正在看Apple的核心图像编程指南.关于多线程,它说:“每个线程必须创建自己的CIFilter对象.否则,你的应用程序可能会出现意外行为.”这是什么意思?我实际上是试图在后台线程上运行我的过滤器,所以我可以在主线程上运行HUD(见下文).这在coreImage的上下文中是否有意义?

  2. ios – 意外的核心数据多线程违规

    我正在使用苹果的并发核心数据调试器.-com.apple.CoreData.ConcurrencyDebug1有时候我得到__Multithreading_Violation_AllThatIsLeftToUsIsHonor__,即使我几乎肯定线程没有被违反.这是发生异常的代码的一部分(代码是扩展NSManagedobject的协议的一部分):代码在上下文的执行:块中执行.这里是线程信息:和调试器

  3. ios – UIGraphicsBeginImageContextWithOptions和多线程

    我对UIGraphicsBeginImageContextWithOptions和线程有点困惑,因为根据UIKitFunctionReferenceUIGraphicsBeginImageContextWithOptions应该只在主线程上调用.当被调用时,它创建一个基于位图的上下文,可以使用CoreGraphics的函数或者像-drawInRect这样的方法来处理:对于UIImage,-draw

  4. Swift之dispatch_source实现多线程定时关闭功能

    由于在项目中需要用到定时关闭音频功能,本来打算用NSTimer的,可是写起来并不是那么精简好用,所以又在网上找到相关的实例,结合自己项目需要,就写出了如下代码,还请大家指教,废话不多说:

  5. swift 多线程实现

  6. swift_多线程基础_最简单用法GCD, NSOperationQueue, NSThread

    ////ViewController.swift//study1-1//Createdbyadminon15/12/28.//copyright2015年admin.Allrightsreserved.//importUIKitclassViewController:UIViewController{@IBOutletvarmyLable:UILabel?@IBActionfuncclickBut

  7. swift__多线程GCD详解

    有以下*-disPATCH_QUEUE_PRIORITY_HIGH:*-disPATCH_QUEUE_PRIORITY_DEFAULT:多用默认*-disPATCH_QUEUE_PRIORITY_LOW:*-disPATCH_QUEUE_PRIORITY_BACKGROUND:*第二个参数为预留参数,一般为0*/letmyQueue:dispatch_queue_t=dispatch_get_global_queue//用异步的方式运行队列里的任务dispatch_async//-------------

  8. Swift - 多线程实现方式3 - Grand Central DispatchGCD

    dispatchqueue可以是并发的或串行的。dispatch_suspend后,追加到DispatchQueue中尚未执行的任务在此之后停止执行。6//创建并行队列conQueue:dispatch_queue_t=dispatch_queue_create//暂停一个队列dispatch_suspend//继续队列dispatch_resume6,dispatch_once一次执行保证dispatch_once中的代码块在应用程序里面只执行一次,无论是不是多线程。注意,我们不能(直接)取消我们已经提

  9. 【Swift】三种多线程处理方式

    )Threadbtn.frame=CGRectMakeThreadbtn.setTitle//普通状态下的文字Threadbtn.setTitle//触摸状态下的文字letmethod:Selector=methodarr[index!]Threadbtn.addTargetself.view.addSubview;}}overridefuncdidReceiveMemoryWarning(){super.didReceiveMemoryWarning()}//1.NSThread线程functestNS

  10. Swift多线程之GCD

    学自:http://www.jianshu.com/p/2598a4e9c139

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部