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

1.0 非阻塞队列

在上篇中,大家讲到了不通队列,以及阻塞队列中的几个落实类。

本篇,大家再三再四对队列进行商讨。而先天的宗旨,则是非阻塞队列!在非阻塞队列中,ConcurrentLinkedQueue是第3代表。

事先,大家询问了什么是阻塞队列,在此我们再简单地想起下!

怎么是阻塞队列?

卡住,顾名思义:当我们的生产者向队列中生产数据时,若队列已满,那么生产线程会暂停下来,直到队列中有能够存放数据的地点,才会三番五次工作;而当大家的买主向队列中获取数据时,若队列为空,则消费者线程会暂停下来,直到容器中有成分出现,才能举办获取操作。

那正是阻塞队列。

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

如何是非阻塞队列?

美学原理,与阻塞队列相反,非阻塞队列的举行并不会被卡住,无论是消费者的出队,照旧劳动者的入队。

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

非阻塞队列的操作

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

入队格局:

add():底层调用offer();

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

出队方法:

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

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

上面,大家切实说下ConcurrentLinkedQueue的原理,以及落实!

ConcurrentLinkedQueue

ConcurrentLinkedQueue是二个线程安全的种类,基于链表结构实现,是三个无界队列,理论上来说队列的尺寸能够极其扩张。

与其余队列相同,ConcurrentLinkedQueue也采纳的是先进先出(FIFO)入队规则,对元素举办排序。当我们向队列中添美成分时,新插入的因素会插入到行列的尾巴;而当大家得到一个要素时,它会从队列的尾部中取出。

因为ConcurrentLinkedQueue是链表结构,所以当入队时,插入的要素依次向后拉开,形成链表;而出队时,则从链表的第①个成分开始获得,依次递增;

不知晓,笔者那样描写能还是无法让你对链表的入队、出队发生四个光景的笔触!

简短利用

值得注意的是,在使用ConcurrentLinkedQueue时,假使波及到行列是或不是为空的判断,切记不可选拔size()==0的做法,因为在size()方法中,是由此遍历整个链表来促成的,在队列成分很多的时候,size()方法丰盛消耗质量和岁月,只是单纯的判断队列为空使用isEmpty()即可!!!

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源码拷出,本地新建2个类,使用run执行,在点子的内外扩充自身的输出语句,打字与印刷出实际的内存地址,便可一探究竟。若是您不想对源码进行改动,只想用debug情势,提议将拷贝源码中的ConcurrentLinkedQueue的接二连三和促成清一色去掉,方式如下:public
class
ConcurrentLinkedQueue<E>
,那样也能够确定保证debug方式的常规运转。