美文网首页java源码解读@IT·互联网程序员
java基础:java.util.concurrent.Bloc

java基础:java.util.concurrent.Bloc

作者: wuxiaowei | 来源:发表于2017-05-29 17:23 被阅读137次

前言

在一次项目中,偶遇BlockingQueue,特意查了下用法,使我对它有了强列的兴趣,经过一段时间的学习,将其整理,用图解的方式解释,方便理解。

介绍

在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。图(1_0.png)是其继承关系,可以看出BlockingQueue是继承Queue。

1_0.png

我们先看下BlockQueue的图解,通过图,我们很容易理解,这是一个队列基本图,在图中,我们发现入队有put、add、offer三个方法。出队有poll、remove、take三个方法,就是因为这几个方法,使得blockQueue功能很强大。

1_1.png

put、add、offer 区别

  • put
    把Object加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.
  • add
    把Object加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则报异常
  • offer
    将Object加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.
    当队列满了,put阻塞,等有了再加,add直接报错,offer返回状态

poll、remove、take 区别

  • take
    取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止
  • remove
    取走BlockingQueue里排在首位的对象,若不能立即取出,则抛出异常
  • poll
    取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,
        取不到时返回null;
    当队列空了,take取不到就等,remove就抛异常,poll就返回null

阻塞模型

  1. 当队列满了,再往队列里put数据就会出现线程等待,模型如下


    Paste_Image.png
  2. 当队列空了,再往队列里take数据,就会出现线程等待,模型如下

Paste_Image.png

实现了BlockingQueue的类

Paste_Image.png

我们常用的队列就linkedBlockingQueue和ArrayBlockingQueue。

LinkedBlockingQueue 和 ArrayBlockingQueue

  • 区别
    我们区分下LinkedBlockingQueue和ArrayBlockingQueue,凡是linked打头的都是内部维护一个链表,Array打头的是维护一个数组,实现方式不一样,功能也有所区别。
  • LinkedBlockingQueue是内部维护一个链表,当执行put方法时,程序会先获得一个重入锁,防止多线程同时操作产生数据不正确,然后后生成一个数据节点(Node)添加到链表的最后面。如果队列满,则使用java.util.concurrent.locks.Condition的await()方法来阻塞继续添加。
    这是put方法源码:
    public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    int c = -1;
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try {
    while (count.get() == capacity) {
    notFull.await();
    }
    enqueue(e);
    c = count.getAndIncrement();
    if (c + 1 < capacity)
    notFull.signal();
    } finally {
    putLock.unlock();
    }
    if (c == 0)
    signalNotEmpty();
    }
    take()取数据也用了await()方法,了解原理后,发现取数据时当链表为空时,就阻塞。
    这是take()方法源码:
    public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
    while (count.get() == 0) {
    notEmpty.await();
    }
    x = dequeue();
    c = count.getAndDecrement();
    if (c > 1)
    notEmpty.signal();
    } finally {
    takeLock.unlock();
    }
    if (c == capacity)
    signalNotFull();
    return x;
    }
  • ArrayBlockingQueue是内部维护一个数组,当执行put方法时,程序也会先获得一个重入锁,防止多纯种同时操作数组,然后直接插入到数组上面,这里和linkedBlockingQueue有个区别就是不会产生一个新的对象节点,开销上插入比LinkedBlockQueue节省空间。
    这是put方法源码:
    public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    final E[] items = this.items;
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    try {
    while (count == items.length)
    notFull.await();
    } catch (InterruptedException ie) {
    notFull.signal(); // propagate to non-interrupted thread
    throw ie;
    }
    insert(e);
    } finally {
    lock.unlock();
    }
    }
  • 总结

这两个队列的实现几乎都是相似的,我们可以理解成对应的数组和链表的实现。并且是线程安全的,在特定场景中使用特定的实现类能保证高效和空间的合理性。

相关文章

  • java基础:java.util.concurrent.Bloc

    前言 在一次项目中,偶遇BlockingQueue,特意查了下用法,使我对它有了强列的兴趣,经过一段时间的学习,将...

  • Java 基础

    Java 基础01Java开发入门 Java 基础02Java编程基础 Java 基础03面向对象 Java 基础...

  • 技术体系

    一,java核心 java基础,jvm,算法,多线程,设计模式 Java基础:java基础相关,全栈java基础 ...

  • 面试题汇总

    1.Java基础面试问题 Java基础之基础问题 Java基础之面向对象 Java基础之数据结构 Java基础之I...

  • 【Android】知识点汇总,坚持原创ing

    Android基础 Java基础 Java基础——Java内存模型和垃圾回收机制 语法基础 语法基础——C语法基础...

  • Java基础:反射

    反射注解动态代理相关阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 ...

  • Java基础:注解

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 1. 概述 注解...

  • Java基础:动态代理

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 概述 在运行时,...

  • Java 集合类原理

    Java基础——HashMap源码分析 Java基础——HashSet源码分析 Java基础——HashTable...

  • Java基础:类加载器

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 1. 什么是类加...

网友评论

    本文标题:java基础:java.util.concurrent.Bloc

    本文链接:https://www.haomeiwen.com/subject/lzpqfxtx.html