互联网技术10——queue队列

  在并发队列上JDK提供了两套实现,一个是已ConcurrentLinkedQueue为代表的高性能队列,一个是以BlockingQueue为代表的阻塞队列。两种都是继承了Queue接口。

层次图(hierarchy):(idea中 层次图快捷键:选中后(或在类中空白处)) ctrl+h )

1.concurrentLinkedQueue:

  concurrentLinkedQueue是一个适用于高并发场景下的队列,通过无锁的方式,实现了高并发状态下的高性能,通常concurrentLinkedQueue性能要好于BlockedQueue。它是一个基于链接节点的无界线程安全队列。该队列元素遵循先进先出的原则。头是最先加入的,尾是最后加入的,该队列不允许有null元素。

  ConcurrentLinkedQueue重要方法:add()、offer()、poll()、peek()

1.  add()和offer()都是加入元素的方法(在concurrentLinkedQueue中,这两个方法没有任何区别,之所以有两个相同的方法,是因为这两个方法都继承自Queue,其他场景可能不一样)。

2.   pool()和peek()都是取头元素,区别在于前者会删除元素,后者不会

验证ConcurrentLinkedQueue是线程安全的:

  

package com.company;

import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Created by BaiTianShi on 2018/8/18.
 */
public class QueueTest {

    public static void main(String[] args) {
         ConcurrentLinkedQueue<String> qu = new ConcurrentLinkedQueue<>();
        qu.add("a");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                if(!qu.isEmpty()){
                    System.out.println("进入t1线程");
                    System.out.println("t1获取的元素"+qu.poll());
                }
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                if(!qu.isEmpty()){
                    System.out.println("进入t2线程");
                    System.out.println("t2获取的元素"+qu.poll());
                }
            }
        },"t2");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                if(!qu.isEmpty()){
                    System.out.println("进入t3线程");
                    System.out.println("t3获取的元素"+qu.poll());
                }
            }
        },"t3");
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                if(!qu.isEmpty()){
                    System.out.println("进入t4线程");
                    System.out.println("t4获取的元素"+qu.poll());
                }
            }
        },"t4");
        Thread t5 = new Thread(new Runnable() {
            @Override
            public void run() {
                if(!qu.isEmpty()){
                    System.out.println("进入t5线程");
                    System.out.println("t5获取的元素"+qu.poll());
                }
            }
        },"t5");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();


    }
}

运行结果:

进入t1线程
进入t3线程
进入t5线程
进入t2线程
t5获取的元素null
t3获取的元素null
t1获取的元素a
进入t4线程
t2获取的元素null
t4获取的元素null

  可见看到,只有一个能拿到非空的值。其他线程拿不到a。在判断队列是否为空时,不要使用size,因为size要遍历一遍集合,使用isEmpty效率比较高,size()方法见下图。

ArrayBlockQueue

  基于数组的阻塞队列实现,在ArrayBlockQueue内部维护里一个定长的数组,以便缓存队列中的数据对象,

猜你喜欢

转载自blog.csdn.net/qq_28240551/article/details/81805059