前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java集合--非阻塞队列(ConcurrentLinkedQueue基础)

Java集合--非阻塞队列(ConcurrentLinkedQueue基础)

作者头像
贾博岩
发布2018-05-11 15:56:47
1.7K0
发布2018-05-11 15:56:47
举报
文章被收录于专栏:博岩Java大讲堂博岩Java大讲堂
1.0 非阻塞队列

在上篇中,我们讲到了阻塞队列,以及阻塞队列中的几个实现类。

本篇,我们继续对队列进行研究。而今天的主题,则是非阻塞队列!在非阻塞队列中,ConcurrentLinkedQueue是主要代表。

之前,我们了解了什么是阻塞队列,在此我们再简单地回顾下!

什么是阻塞队列?

阻塞,顾名思义:当我们的生产者向队列中生产数据时,若队列已满,那么生产线程会暂停下来,直到队列中有可以存放数据的地方,才会继续工作;而当我们的消费者向队列中获取数据时,若队列为空,则消费者线程会暂停下来,直到容器中有元素出现,才能进行获取操作。

这就是阻塞队列。

那么,非阻塞队列又是什么含义呢?

什么是非阻塞队列?

与阻塞队列相反,非阻塞队列的执行并不会被阻塞,无论是消费者的出队,还是生产者的入队。

在底层,非阻塞队列使用的是CAS(compare and set)来实现线程执行的非阻塞。

非阻塞队列的操作

与阻塞队列相同,非阻塞队列中的常用方法,也是出队和入队。

入队方法:

代码语言:javascript
复制
add():底层调用offer();

offer():Queue接口继承下来的方法,实现队列的入队操作,不会阻碍线程的执行,插入成功返回true;

出队方法:

代码语言:javascript
复制
poll():移动头结点指针,返回头结点元素,并将头结点元素出队;队列为空,则返回null;

peek():移动头结点指针,返回头结点元素,并不会将头结点元素出队;队列为空,则返回null;

下面,我们具体说下ConcurrentLinkedQueue的原理,以及实现!

ConcurrentLinkedQueue

ConcurrentLinkedQueue是一个线程安全的队列,基于链表结构实现,是一个无界队列,理论上来说队列的长度可以无限扩大。

与其他队列相同,ConcurrentLinkedQueue也采用的是先进先出(FIFO)入队规则,对元素进行排序。当我们向队列中添加元素时,新插入的元素会插入到队列的尾部;而当我们获取一个元素时,它会从队列的头部中取出。

因为ConcurrentLinkedQueue是链表结构,所以当入队时,插入的元素依次向后延伸,形成链表;而出队时,则从链表的第一个元素开始获取,依次递增;

不知道,我这样形容能否让你对链表的入队、出队产生一个大概的思路!

简单使用

值得注意的是,在使用ConcurrentLinkedQueue时,如果涉及到队列是否为空的判断,切记不可使用size()==0的做法,因为在size()方法中,是通过遍历整个链表来实现的,在队列元素很多的时候,size()方法十分消耗性能和时间,只是单纯的判断队列为空使用isEmpty()即可!!!

代码语言:javascript
复制
public class ConcurrentLinkedQueueTest {

    public static int threadCount = 100000;

    public static ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>();

    static class Offer implements Runnable {
        public void run() {
            if(queue.size()==0){
                String ele = new Random().nextInt(Integer.MAX_VALUE)+"";
                queue.offer(ele);
                System.out.println("入队元素为"+ele);
            }
        }
    }

    static class Poll implements Runnable {
        public void run() {
            if(!queue.isEmpty()){
                String ele = queue.poll();
                System.out.println("出队元素为"+ele);
            }
        }
    }

    public static void main(String[] agrs) {
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        for(int x=0;x<threadCount;x++){
            executorService.submit(new Offer());
            executorService.submit(new Poll());
        }
        executorService.shutdown();
    }
}

下篇中,我们详细来介绍ConcurrentLinkedQueue的底层实现。

引言:在笔者研究源码时,发现无论是idea,还是eclipse,在debug模式下,跟踪ConcurrentLinkedQueue源码时都会产生bug,具体情况就是debug控制台中类的内存地址和实际的内存地址不一致,导致代码在debug执行时并不会按照正常逻辑来执行。

详细描述,可参考如下内容:神奇的控制台

解决方案:将ConcurrentLinkedQueue源码拷出,本地新建一个类,使用run执行,在方法的前后增加自己的输出语句,打印出实际的内存地址,便可一探究竟。如果你不想对源码进行修改,只想用debug模式,建议将拷贝源码中的ConcurrentLinkedQueue的继承和实现统统去掉,形式如下:public class ConcurrentLinkedQueue<E>,这样也可以保证debug模式的正常运行。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.12.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.0 非阻塞队列
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档