1. 构造方法:public ArrayBlockingQueue(int capacity) {
    this(capacity, false);
    }
  2.  
  3. public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
    throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    notEmpty = lock.newCondition();
    notFull = lock.newCondition();
    }
  4.  
  5. ArrayBlockingQueue的内部元素都放在一个对象数组中 items /** The queued items */ final Object[] items;
    添加元素的时候用 offer()和put()方法。用offer方法的时候如果数组已经满了,那么会返回false。但是put方法
    如果数组满了的话那么他会一直等待,知道队列中有空闲的位置。
    offer方法源码:
    public boolean add(E e) {
    return super.add(e);
    }
    public boolean offer(E e) {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lock(); // 一直等到获取锁
    try {
    if (count == items.length) //假如当前容纳的元素个数已经等于数组长度,那么返回false
    return false;
    else {
    enqueue(e); // 将元素插入到队列中,返回true
    return true;
    }
    } finally {
    lock.unlock(); //释放锁
    }
    }
    put方法源码:
    public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); //可中断的获取锁
    try {
    while (count == items.length) //当线程从等待中被唤醒时,会比较当前队列是否已经满了
    notFull.await(); //notFull = lock.newCondition 表示队列不满这种状况,假如现场在插入的时候
    enqueue(e); //当前队列已经满了时,则需要等到这种情况的发生。
    } finally { //可以看出这是一种阻塞式的插入方式
    lock.unlock();
    }
    }
  6.  
  7. 如果我们想要取出元素,那么我们可以采用 poll()和take()方法,如果队列中没有元素了,那么poll会返回null,但是take不会,他会一直等待,直到队列有可用的元素。
  8.  
  9. poll()方法源码:
  10.  
  11. public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    return (count == 0) ? null : dequeue(); //假如当前队列中的元素为空,返回null,否则返回出列的元素
    } finally {
    lock.unlock();
    }
    }
  12.  
  13. take源码:
  14.  
  15. take方法和put方法相互对应,他一定要拿到一个元素,除非线程被中断。
  16.  
  17. public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    while (count == 0) //线程在刚进入 和 被唤醒时,会查看当前队列是否为空
    notEmpty.await(); //notEmpty=lock.newCondition表示队列不为空的这种情况。假如一个线程进行take
    return dequeue(); //操作时,队列为空,则会一直等到到这种情况发生。
    } finally {
    lock.unlock();
    }
    }
  18.  
  19. peek源码:
  20.  
  21. 如前文所说,peek方法不会真正的从队列中删除元素,实际上只是取出头元素而已。
  22.  
  23. public E peek() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    return itemAt(takeIndex); // null when queue is empty
    // 实际上 itemAt 方法就是 return (E) items[i];
    //也就是说 返回 数组中的第i个元素。 } finally { lock.unlock(); }}
    remove源码:
  24.  
  25. remove方法实现在Abstract方法中,很容易看懂,里面就是走的poll方法。
  26.  
  27. public E remove() {
    E x = poll();
    if (x != null)
    return x;
    else
    throw new NoSuchElementException();
    }
  28.  
  29. enqueue源码:
  30.  
  31. 我们再来看看真正得到入队操作,不然光看上面的截图也不明白不是。
  32.  
  33. private void enqueue(E x) { //因为调用enqueue的方法都已经同步过了,这里就不需要在同步了
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items;
    items[putIndex] = x; //putIndex是下一个放至元素的坐标
    if (++putIndex == items.length) //putIndex+1, 并且比较是否与数组长度相同,是的话,则从数组开头
    putIndex = 0; //插入元素,这就是循环数组的奥秘了
    count++; //当前元素总量+1
    notEmpty.signal(); //给等到在数组非空的线程一个信号,唤醒他们。
    }
  34.  
  35. dequeue源码:
  36.  
  37. 当然,我们也要看一下出对的操作
  38.  
  39. private E dequeue() {
    // assert lock.getHoldCount() == 1;
    // assert items[takeIndex] != null;
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null; //将要取出的元素指向null 表示这个元素已经取出去了
    if (++takeIndex == items.length) //takeIndex +1,同样的假如已经取到了数组的末尾,那么就要重新开始取
    takeIndex = 0; //这就是循环数组
    count--;
    if (itrs != null)
    itrs.elementDequeued(); //这里实现就比较麻烦,下次单独出一个吧,可以看看源码
    notFull.signal(); //同样 需要给 等待数组不满这种情况的线程一个信号,唤醒他们。
    return x;
    }
  40.  
  41. 练习的例子:
  42.  
  1. package BlockQueueTEst;
  2.  
  3. import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingDeque;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
  4.  
  5. /**
    * Created by zzq on 2018/2/27.
    */
    public class BTest {
    static ArrayBlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(3);
    private static class TestT implements Runnable{
  6.  
  7. public void run() {
    try {
    System.out.println(blockingQueue.take());
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    ;
    }
    }
    private static class TestT2 implements Runnable{
  8.  
  9. public void run() {
    blockingQueue.offer("1");
    }
    }
    // public static void main(String[] args) throws InterruptedException {
    // blockingQueue.offer("1");
    // blockingQueue.offer("2");
    // blockingQueue.offer("3");
    // blockingQueue.offer("4");
    // blockingQueue.poll();
    // blockingQueue.poll();
    //
    // blockingQueue.offer("5");
    // System.out.println(blockingQueue.peek());
    //
    //// LinkedBlockingQueue linkedBlockingQueue=new LinkedBlockingQueue();
    // }
    public static void main(String[] args) throws InterruptedException {
    Thread t1=new Thread(new TestT());
    Thread t2=new Thread(new TestT2());
    t1.start();
    Thread.sleep(2000);
    t2.start();
    }
    }
  1.  

3.3.6-1 ArrayBlockingQueue简单分析的更多相关文章

  1. 简单分析ThreadPoolExecutor回收工作线程的原理

    最近阅读了JDK线程池ThreadPoolExecutor的源码,对线程池执行任务的流程有了大体了解,实际上这个流程也十分通俗易懂,就不再赘述了,别人写的比我好多了. 不过,我倒是对线程池是如何回收工 ...

  2. 简单分析JavaScript中的面向对象

    初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...

  3. CSipSimple 简单分析

    简介 CSipSimple是一款可以在android手机上使用的支持sip的网络电话软件,可以在上面设置使用callda网络电话.连接使用方式最好是使用wifi,或者3g这样上网速度快,打起电话来效果 ...

  4. C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析与解决方法

    对于C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析,目前本人分析两种情况,如下: 情况一: 借鉴麒麟.NET ...

  5. 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化

    序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...

  6. 简单分析Java的HashMap.entrySet()的实现

    关于Java的HashMap.entrySet(),文档是这样描述的:这个方法返回一个Set,这个Set是HashMap的视图,对Map的操作会在Set上反映出来,反过来也是.原文是 Returns ...

  7. Ffmpeg解析media容器过程/ ffmpeg 源代码简单分析 : av_read_frame()

    ffmpeg 源代码简单分析 : av_read_frame() http://blog.csdn.net/leixiaohua1020/article/details/12678577 ffmpeg ...

  8. FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  9. FFmpeg资料来源简单分析:libswscale的sws_getContext()

    ===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...

随机推荐

  1. USB驱动程序之USB设备驱动程序1简单编写

    1.驱动编写分析 (1)usb总线驱动程序在我们接入USB设备的时候会帮我们构造一个新的usb_device.注册到总线里面来.左边这一块已经帮我们做好了,我们要做的是右边这一块.我们要构造一个usb ...

  2. SharePoint 事件 7363:对象缓存:缓存使用的超级读者帐户没有足够的权限访问SharePoint数据库。

    转自MSND:http://technet.microsoft.com/zh-cn/library/ff758656(v=office.14) 对象缓存存储 Microsoft SharePoint ...

  3. spring boot + slf4j + log4j配置

    https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/htmlsingle/#boot-features-logging ht ...

  4. spring 配置双数据源并读写分离

    摘自 开源项目Ibase4j    关键思想在于AbstractRoutingSource 类 还有方法名称和切入点去控制使用哪个数据源    1.首先在配置文件配置多个数据源 并且交给继承自spri ...

  5. 【转】浅析VO、DTO、DO、PO的概念、区别和用处

    原文地址:http://blog.csdn.net/zjrbiancheng/article/details/6253232 概念: VO(View Object):视图对象,用于展示层,它的作用是把 ...

  6. DNS_PROBE_FINISHED_NXDOMAIN

    DNS_PROBE_FINISHED_NXDOMAIN 用如下链接清除dns即可 chrome://net-internals/#dns dns不稳定 手动绑定host即可

  7. 前端调试利器---nproxy

    前言:习惯了在windows环境中使用Fiddler的童鞋们,是不是感觉它的网络重定向功能很酷,Fiddler能按照你设置的规制捕获网络请求,再指向本地文件,如拦截你的js文件到本地,就能很快的调试线 ...

  8. 给虚拟机添加eth1网络适配器(网卡)

    1.虚拟机 -- > 设置 2.添加 --> 网络适配器 --> 下一步 3.主机 -- > 完成 -- > 确定 4.修改网卡的配置文件 cd /etc/sysconf ...

  9. U3D中物体的渲染顺序

    1,由SHADER中渲染队列及队列中的值决定 2,在同一队列中,若材质相同 2.1 对于UI,按其在场景层级中的先后顺序绘制 2.2 对于3D不透明物体,按其离相机的距离,由近到远绘制,这样可以减少像 ...

  10. shell编程——sed用法

    一.sed格式: sed 参数 '正则表达式' 文件名 演示文件的内容: [root@localhost ~]# cat test.sh #!/bin/bash 第一行 12345! 第二行 2345 ...