Java集合–非阻塞队列(ConcurrentLinkedQueue基础)美学原理

1.0 非阻塞队列

在直达篇被,我们说话到了绿灯队列,以及阻塞队列中的几乎单落实类似。

本篇,我们继续指向队列举办探讨。而前日之主旨,则是非阻塞队列!在非阻塞队列中,ConcurrentLinkedQueue是要代表。

事先,大家询问了什么是死队列,在这我们又简单地回顾下!

好家伙是死队列?

卡住,顾名思义:当大家的劳动者向行中生数据时,若队列已满,那么生产线程会暂停下来,直到队列中发生得存放数据的地点,才晤面继续工作;而当我们的客向行中获取数据时,若队列为空,则消费者线程会暂停下来,直到容器中起素出现,才可以举办得操作。

随即即是死队列。

这,非阻塞队列又是啊意思呢?

好家伙是非阻塞队列?

暨死队列相反,非阻塞队列的施行并无会合叫堵塞,无论是消费者的出队,如故劳动者的入队。

以底部,非阻塞队列使用的是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源码拷出,本地新建一个看似,使用run执行,在法的光景增添自己的输出语句,打印出实际的内存地址,便可同等研究竟。假若你无惦念对源码举办改动,只想就此debug格局,指出用拷贝源码中的ConcurrentLinkedQueue的接轨和促塔林去丢,形式如下:public
class
ConcurrentLinkedQueue<E>
,那样吗可以保debug形式的健康运行。