ArrayBlockingQueue-我们到底能走多远系列(42)

我们到底能走多远系列(42)

扯淡:

  乘着有空,读些juc的源码学习下。后续把juc大致走一边,反正以后肯定要再来。

主题:

BlockingQueue 是什么

A java.util.Queue that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element.

一个能阻塞的队列在两个操作队列时的阻塞:

  1,获取队列中元素时,队列为空,则阻塞,直到队列中有元素。

  2,存放一个元素时,队列已满,则阻塞,直到队列中有空位置可以存放。

BlockingQueue 作为接口规定了实现的规矩。

下面是队列核心的存取操作方法的4个种类:

  Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e, time, unit)
Remove remove() poll() take() poll(time, unit)
Examine element() peek() not applicable not applicable

根据上面表,在队列满或空时的策略分别包含了,抛出异常,返回boolean值,阻塞线程,阻塞到超时。

为什么要这么选择,就不清楚了。我们需要注意的是除了第三种,其他方法都没有真正阻塞线程。

ArrayBlockingQueue:

内部用数组实现的一个queue,按照元素先进先出(FIFO)原则。初始化后,队列容量不可改变。

支持可选的公平机制,来保证阻塞的操作线程能按照顺序排列等待。默认是不公平机制。

源码实现:

1,使用Object[]的一个数组来存储元素

// 队列存放元素的容器
final Object[] items;

// 下一次读取或移除的位置
int takeIndex;

// 存放下一个放入元素的位置
int putIndex;

// 队列里有效元素的数量
int count;

// 所有访问的保护锁
final ReentrantLock lock;

// 等待获取的条件
private final Condition notEmpty;

// 等待放入的条件
private final Condition notFull;

2,整个队列是有一个环绕机制的,比如这时候我一直取数据,那么读取的下标会一直后移,知道数组的末尾。如果这时候制定数组的尾部后一个下标时数组的头位。如此即实现环绕的一个队列。如此实现十分精妙,可说是整个队列实现的基础机制。

如此,这个队列的容量是不可改变的。

// 指针前移
final int inc(int i) {
    return (++i == items.length) ? 0 : i;
}

// 指针后移
final int dec(int i) {
    return ((i == 0) ? items.length : i) - 1;
}

3,直接看下核心的put和take方法实现:

put

    public void put(E e) throws InterruptedException {
        checkNotNull(e);//不能放null
        final ReentrantLock lock = this.lock;//先把锁赋给final修饰的局部变量
        // 在JUC的很多类里,都会看到这种写法:把类的属性赋值给方法内的用final修饰一个变量。
        // 这是因为类的属性是存放在堆里的,方法内的变量是存放在方法栈上的,访问方法栈比访问堆要快。
        // 在这里,this.lock属性要访问两次,通过赋值给方法的局部变量,就节省了一次堆的访问。
        // 其他的类属性只访问一次就不需要这样处理了。
        lock.lockInterruptibly();//加锁
        try {
            //循环保证避免避免虚假唤醒,虚假唤醒就是此事如果有多个线程都wait,       //而被同时唤醒时都会去执行下面的insert
            //如果在while循环中,那么唤醒后先判断count大小,来确定是继续wait还是insert。
            while (count == items.length)
                notFull.await();//阻塞线程
            insert(e);
        } finally {
            lock.unlock();//释放锁
        }
    }

take

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return extract();
        } finally {
            lock.unlock();
        }
    }

其中使用到insert和extract方法,当然也可以看到只有持有锁的情况下才会调用这两个方法,如此这个方法的调用不需要关系是否线程安全,调用前保证线程安全:

    private void insert(E x) {
        items[putIndex] = x;// 1,存值,非常简便
        putIndex = inc(putIndex);//2,移动下标,使用inc方法
        ++count;//3,增加元素总数
        notEmpty.signal();//4,通知在非空条件上等待的读线程
    }
    private E extract() {
        final Object[] items = this.items;//先将类变量赋给方法变量,前面提过这个用处
        E x = this.<E>cast(items[takeIndex]);
        items[takeIndex] = null;
        takeIndex = inc(takeIndex);
        --count;
        notFull.signal();
        return x;
    }

操作示意图:

1,一个环的数组

2,再放一个元素:

3,取一个元素

当然ArrayBlockingQueue里还有其他方法,这里就不赘述了。有兴趣的同学可以深入继续探索。

总结:

 1,一个环的数组设计十分巧妙。

 2,将类变量赋给方法变量的编码方式

 

让我们继续前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不会成功。

时间: 2024-10-09 07:27:02

ArrayBlockingQueue-我们到底能走多远系列(42)的相关文章

ThreadPoolExecutor机制探索-我们到底能走多远系列(41)

我们到底能走多远系列(41) 扯淡: 这一年过的不匆忙,也颇多感受,成长的路上难免弯路,这个世界上没人关心你有没有变强,只有自己时刻提醒自己,不要忘记最初出发的原因. 其实这个世界上比我们聪明的人无数,很多人都比我们努力,当我门奇怪为什么他们可以如此轻松的时候,是不会问他们付出过什么.怨天尤人是无用的,使自己变好,哪怕是变好一点点,我觉得生活着就是有意义的. 未来,太远.唯有不停的积累,不要着急,抓得住的才能叫机会. 羊年,一定要不做被动的人.大家加油! 目录留白: 主题: 直接进ThreadP

springmvc对同名参数处理-我们到底能走多远系列(44)

springmvc对同名参数处理 扯淡: 中断发博客几个月,其实蛮不爽的,可能最近太忙太劳累了些,很多总结也没时间写,今天刚好遇到个小问题,就阅读下源码找找乐.因为考虑到网上大多是提供解决问题的方案,没有实际去看spring源码流程,所以就发个博文记录下,万一以后有同学搜到我的文章能深入看些东西吧. 问题描述: 前端有多个相同name的input: <input type="text" min="1" max="31" name="

日志打入kafka改造历程-我们到底能走多远系列49

方案 日志收集的方案有很多,包括各种日志过滤清洗,分析,统计,而且看起来都很高大上.本文只描述一个打入kafka的功能. 流程:app->kafka->logstash->es->kibana 业务应用直接将日志打入kafka,然后由logstash消费,数据进入es. 另一方面,应用在服务器上会打日志文件. 如图: 详细 初步实现 首先,我们来初步实现这个方案,搭建elk略去不谈,其中特别注意各个版本的兼容.这里主要在代码层面讲解如何实现的历程. 要将日志数据写入kafka,我们

能定位能导航的室内地图平台到底能走多远?

现今社会万物相连的物联网时代,那么什么是物联网呢?物联网就是在互联网的基础上进行延伸和扩展,另外在延伸与扩展之间,进行物品与物品之间的联系,进行信息交换与通信.在进行信息交换时,信息位置作为一个重要角色而被突显出来,而通过信息位置的突显衍生出各种关于位置信息的服务.例如室内地图就是由物联网时代衍生出的位置信息服务! 随着城市建设脚步的加快,各种各样的室内环境也随之形成(如大型商场.机场.车站等),同样也带来了一个重要的问题,当处在室内环境中需要寻找指定目标时,往往是非常苦恼的,不知道如何寻找目标

不懂编程的运维人员到底还能走多远?

不懂编程的运维还能走多远? 且看行业内一流专家老男孩老师的深度细致分析! 首先,可以肯定的说,未来的IT岗位需要的是综合能力强的人员,运维.开发.数据库.网络,技术岗位对上述知识体系都要会一些,才能很好的胜任对应岗位工作. 下面已经不是趋势,而是菜鸟及老鸟都必须要认真考虑的: 1.运维人员要会运维.开发.数据库.网络,但侧重点是运维, 2.开发人员要会运维.开发.数据库.网络,但侧重点是开发, 3.数据库人员要会运维,开发,数据库,网络,但侧重点是数据库, 4.网络人员要会运维,开发,数据库,网

整装时代的互联网家装,能走多远?

规模已达近4万亿并且还在膨胀的巨大家装市场,吸引了包括小米.新美大.淘宝.京东等互联网公司前来掘金.它们试图从各个环节渗入这个利润可观的市场中,重新挖掘其中利润点.但最近不断爆出的投诉.工人跑路.质量问题再度让人们开始冷静看待这个被吹到风口的新事物. 699元,乃至599元等一包到底的互联网白菜价,在整装这个环节多.客户要求千奇百怪的庞大体系中,究竟能换来多少满意度?自身没有施工团队的互联网家装平台,真是套上互联网壳子的"空中楼阁"吗?在这样以中介为主的模式下,互联网家装还能走多远?

知识的共享经济还能走多远

共享经济从2014年开始便甚嚣尘上,仿佛成为了一剂万能灵药,使得很多平台心向往之.其实共享经济本身并没有什么神秘,简单来说,就是通过聚合和调动个人资源,使其规模化地成为社会资源,为全人类所共享. 如今,知识共享经济也应运而生,知乎平台和果壳旗下的在行都打着共享经济的旗号,纷纷推出了知乎Live和分答,包括最近崭露头角的『智应APP』也想借此东风,并且声称自己会在知识共享之路上走到底. 然而,谎话说了太多就成真不了,到底哪家说的是真,哪家说的是假呢? 知乎的转型意味着它再也不是当年的知乎了 不可否

我愿在程序员这条路越走越远

今天偶尔和朋友谈起,他对于我选择IT表示很是惊讶,因为IT和我以前学的专业完全不对口.他还说程序猿应该都是比较闷骚的人,本想反驳一句,但想想应该说的没差.因为我的第一感觉也是这样的. 大概是对于新鲜事物的求知欲,刚刚接触就被这神奇的一门语言所吸引.输入一些字符串就能产生各种指令,真是太新鲜了. 以前作为使用者,对这些方便人类.促使人类进步的科技,总是爱不释手,手机.电脑.游戏,我们能从中体会到快乐,这些都是靠那些开发者.每一样东西的创造都是不易的,看似简单的东西,也许就是别人一辈子的心血.程序猿

疑惑:八卦掌趟泥步到底怎样走才正确?

--> 疑惑:八卦掌趟泥步到底怎样走才正确? 提交 我的留言 加载中 已留言 疑惑:八卦掌趟泥步到底怎样走才正确? 2016-06-08 佚名 功夫天下 功夫天下 功夫天下 微信号 kf_china 功能介绍 发扬中华武术精神,传承民族体育文化! 练八卦步先练直蹚泥步,练的蹚步平稳了再练走圈蹚泥步:然后学练站八卦桩,而后再学练掌.由开始蹚不出去步,练得趟出去而又稳健.八卦趟泥步利于气往下沉,主要练习重心的水平移动,它比形意的直线水平移动要难,因为它要走圈,人体的重心要在一个水平的圆圈上移动.八卦