阻塞队列BlockingQueue(JDK8)

  1. BlockingQueue(阻塞队列)是JDK5新增的线程安全的高效队列类,基于生产者-消费者模式。队列为空时,获取元素的操作等待队列变为非空;队列已满时插入操作等待队列空间可用。
  2. BlockingQueue不接受null元素,会throw NullPointerException,null用于标记poll操作的失败。
  3. BlockingQueue默认容量大小为Integer.MAX_VALUE,支持自定义容量大小。类似于Collection接口,支持remove(x),然而由于性能问题并不推荐大量使用。drainTo(c)比重复poll更高效。
  4. BlockingQueue本质上不提供close、shutdown操作用来标记“不再有元素继续被添加”,开发者可自行定义特殊元素来表示“不再有元素继续被添加”。
  5. 本文地址:http://blog.csdn.net/u010887744/article/details/70195270

方法   操作成功 一直阻塞直到处理成功 失败返回特殊值 失败抛异常
插入 add(e) true     队列已满则IllegalStateException: Queue full
offer(e) true   队列已满:false  
put(e) void 一直阻塞直到插入成功    
offer e,timeout, unit) true   插入超时:false  
addAll(c) true   部分插入异常返回false 队列已满则IllegalStateException: Queue full
移除/获取 remove() 返回被移除的元素     队列为空:抛出NoSuchElementException
remove(e) true   不存在该元素:false  
removeAll(c) 迭代remove(e),队列因此请求而改变则返回true   false  
poll() 队列头   队列为空返回null而不是抛异常  
poll(timeout,unit) 队列头   取数据超时(一直无可返回的对象):返回null  
drainTo(c):将[所有]可用元素加入集合c 集合转移数据个数      
drainTo(c,max):移除最多max个元素并将其加入集合c 集合转移数据个数      
take() 队列头 一直阻塞,直到取回数据    
removeIf(filter) JDK8可用;remove成功任何一个元素即返回true   false  
retainAll(c):数据保留 队列因此请求而改变则返回true   没有remove任何一个元素即返回false  
clear() void      
检测(取回但不移除) element() 队列头     队列为空throw NoSuchElementException
peek() 队列头   队列为空返回null  
contains(e) true   false  
containsAll(c) true   false  
isEmpty() true   false  


其他操作:
  • size():队列大小。
  • remainingCapacity():可用大小。
  • toArray():返回包含集合所有元素的数组,数组顺序和原有集合一致。返回的数组存在于新的内存空间,和原有队列的修改操作不会互相影响。
  • toArray(arr[]):待储存集合空间充足,将队列所有元素按序存于数组,并将多余元素置为null;待储存集合空间不足,将队列所有元素按序存于【新的数组】。
  • forEach(Consumer action)、parallelStream()、spliterator().forEachRemaining、removeIf(filter)等JDK8新增特性见测试代码。
Note:
  • addAll(c)内部结构为foreach遍历add(e),所以可能部分数据插入成功,部分插入失败。
  • drainTo(c)是将队列元素添加到集合c;toArray()是将队列元素覆盖集合元素c。
  • remove(x),由于性能问题并不推荐大量使用;drainTo(c)比重复poll更高效

相关测试代码如下:
Note:可访问 github.zxiaofan.com 查看最新代码: https://github.com/zxiaofan/JDK-Study/tree/master/src/java1/util/concurrent/blockingQueue

/*
 * 文件名:BlockingQueue_Study.java
 * 版权:Copyright 2007-2017 zxiaofan.com. Co. Ltd. All Rights Reserved. 
 * 描述: BlockingQueue_Study.java
 * 修改人:zxiaofan
 * 修改时间:2017年4月11日
 * 修改内容:新增
 */
package java1.util.concurrent.blockingQueue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;

import org.junit.Test;

/**
 * @author zxiaofan
 */
public class BlockingQueue_Study {
    BlockingQueue blockingQueue = new LinkedBlockingQueue(5); // <队列对象String>(队列容量)

    List list = Arrays.asList("list1", "list2");

    /**
     * 插入操作:插入元素为null时将抛出NullPointerException.
     * 
     */
    @Test
    public void BlockingQueueInsertTest() {
        // add-AbstractQueue
        boolean add = blockingQueue.add("add"); // 插入成功:true;阻塞队列已满:抛出java.lang.IllegalStateException: Queue full
        System.out.println("add:" + add);
        boolean offer = blockingQueue.offer("offer"); // 插入成功:true;队列已满:false;
        System.out.println("offer:" + offer);
        try {
            blockingQueue.put("put"); // 无返回值;一直阻塞直到插入成功;线程被中断即Thread.interrupted()时:抛出InterruptedException
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            boolean offer_timeout = blockingQueue.offer("offer_timeout", 3, TimeUnit.SECONDS); // 插入成功:true;插入超时:false;线程被中断即Thread.interrupted()时:抛出InterruptedException
            System.out.println("offer_timeout:" + offer_timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        boolean addAll = false;
        try {
            // addAll-AbstractQueue
            addAll = blockingQueue.addAll(list); // 插入成功:true;内部结构为foreach遍历add(e),所以可能部分数据插入成功,部分插入失败
        } catch (Exception e) { // 吃掉异常
            System.err.println("addAll_Exception:" + e.getMessage());
            // e.printStackTrace();
        }
        System.out.println("addAll:" + addAll);
        System.out.println(blockingQueue.toString());
    }

    /**
     * 阻塞队列移除操作.
     * 
     */
    @Test
    public void BlockingQueueRemoveTest() {
        BlockingQueueInsertTest();
        // remove-AbstractQueue
        String remove = blockingQueue.remove(); // 移除队列头。移除成功:返回被移除的元素;队列为空:抛出NoSuchElementException
        System.out.println("remove:" + remove);
        boolean removeObj = blockingQueue.remove("offer"); // 用equals()判断两个对象是否相等。移除成功:true;不存在该元素:false
        System.out.println("removeObj:" + removeObj);
        String poll = blockingQueue.poll(); // 移除队列头。和remove()的唯一区别在于,当队列为空返回null而不是抛异常
        System.out.println("poll:" + poll);
        try {
            String poll_timeout = blockingQueue.poll(3, TimeUnit.SECONDS); // 移除成功:返回被移除的元素;移除超时(一直无可移除的对象):返回null;线程被中断抛InterruptedException
            System.out.println("poll_timeout:" + poll_timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            String take = blockingQueue.take(); // 一直阻塞,直到取回数据;等待时被中断则抛出InterruptedException
            System.out.println("take:" + take);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        blockingQueue.add("list1");
        boolean removeAll = blockingQueue.removeAll(list); // Iterator it = iterator();迭代remove(),只要remove成功一个且不抛异常就返回false
        System.out.println("removeAll:" + removeAll);
        System.out.println(blockingQueue.toString());
        blockingQueue.addAll(list);
        Predicate filter = (p) -> p.startsWith("list");
        boolean removeIf = blockingQueue.removeIf(filter); // JDK8可用;remove成功任何一个元素即返回true
        System.out.println("removeIf:" + removeIf);
        System.out.println(blockingQueue.toString());
        //
        System.out.println("数据保留");
        BlockingQueueInsertTest();
        // retailAll-AbstractCollection
        boolean retainAll = blockingQueue.retainAll(list); // 队列因此请求而改变则返回true,没有remove任何一个元素即返回false
        System.out.println("retainAll:" + retainAll);
        System.out.println(blockingQueue.retainAll(Arrays.asList("retailAll")));
        System.out.println(blockingQueue.retainAll(list)); // 没有remove任何一个元素即返回false
        System.out.println(blockingQueue.toString());
        blockingQueue.clear(); // 移除所有元素,clear首先加锁fullyLock()
    }

    /**
     * 阻塞队列的cheek:element()/peek().
     * 
     */
    @Test
    public void BlockingQueueCheckTest() {
        BlockingQueueInsertTest();
        String element = blockingQueue.element(); // 取回但不移除队首元素,队列为空throw NoSuchElementException
        System.out.println("element:" + element);
        String peek = blockingQueue.peek(); // 取回但不移除队首元素,队列为空返回null
        System.out.println("peek:" + peek);
        boolean contains = blockingQueue.contains("add"); // 有一元素equals即返回true
        System.out.println("contains:" + contains);
        boolean containsAll = blockingQueue.containsAll(Arrays.asList("add", "offerNew")); // contains所有元素即返回true
        System.out.println("containsAll:" + containsAll);
        boolean isEmpty = blockingQueue.isEmpty(); // 队列无元素即返回true
        System.out.println("isEmpty:" + isEmpty);
    }

    @Test
    public void BlockingQueueOtherTest() {
        BlockingQueueInsertTest();
        // 容量
        System.out.println("size:" + blockingQueue.size());
        int remainingCapacity = blockingQueue.remainingCapacity();
        System.out.println("remainingCapacity:" + remainingCapacity);
        // 遍历
        Consumer consumer = e -> e = e + "_New"; // 将所有元素拼接一个"_New",实际blockingQueue队列元素并为改变,因为String具有不可变性
        blockingQueue.forEach(consumer); // JDK8
        System.out.println("consumer:" + blockingQueue.toString());
        blockingQueue.forEach(e -> {
            System.out.println(e + "_New"); // 遍历每个元素拼接"_New"并打印
        });
        int sum = blockingQueue.parallelStream().filter(p -> p.length() > 4).mapToInt(p -> p.length()).sum();
        System.out.println("JDK8流处理(字符串长度大于4的元素的字符长度和):" + sum);
        blockingQueue.spliterator().forEachRemaining(e -> {
            System.out.println(e + "_FER");
        }); // forEachRemaining:JDK8迭代器默认方法,为集合所有未处理元素执行Action
        // drainTo
        // 比重复poll更高效。drainTo操作时会加锁(ReentrantLock),add操作将等待,故正如Java Doc描述drainTo(Collection c)会将[所有]可用元素加入集合c。
        int actualSize = blockingQueue.size() - blockingQueue.remainingCapacity(); // 队列实际元素个数
        List listDrain = new ArrayList(actualSize);
        new Thread(new Runnable() {

            @Override
            public void run() {
                blockingQueue.add("drainToNew"); // 调试时在此行加断点
            }
        }).start();
        int drainTo = blockingQueue.drainTo(listDrain); // 此行断点调试内部
        // listDrain、blockingQueue都可能有值(并非drainTo未移除所有元素,而是drainTo后又add了新元素)
        System.out.println("drainTo:" + drainTo + ",listDrain:" + listDrain.toString() + ",blockingQueue:" + blockingQueue.toString());
        BlockingQueueInsertTest();
        listDrain.clear();
        int drainToMax = blockingQueue.drainTo(listDrain, 3); // 移除最多max个元素并将其加入listDrain
        System.out.println("drainToMax:" + drainToMax + ",listDrain:" + listDrain.toString() + ",blockingQueue:" + blockingQueue.toString());
        Object[] toArray = blockingQueue.toArray(); // 返回包含集合所有元素的数组,数组顺序和原有集合一致。返回的数组存在于新的内存空间,和原有队列的修改操作不会互相影响。
        System.out.println("toArray:" + Arrays.asList(toArray).toString());
        String[] arrToArray = new String[]{"arr1", "arr2", "arr3"}; // 待储存集合空间充足,将队列所有元素按序存于数组,并将多余元素置为null
        String[] toArrayT = blockingQueue.toArray(arrToArray);
        System.out.println("toArrayT:" + Arrays.asList(toArrayT).toString());
        String[] arrToArray2 = new String[]{"arr1"}; // 待储存集合空间不足,将队列所有元素按序存于【新的数组】
        String[] toArrayT2 = blockingQueue.toArray(arrToArray2);
        System.out.println("toArrayT2:" + Arrays.asList(toArrayT2).toString());
    }
}

欢迎个人转载,但须在文章页面明显位置给出原文连接;
未经作者同意必须保留此段声明、不得随意修改原文、不得用于商业用途,否则保留追究法律责任的权利。

【 CSDN 】:csdn.zxiaofan.com
【GitHub】:github.zxiaofan.com

如有任何问题,欢迎留言。祝君好运!
Life is all about choices! 
将来的你一定会感激现在拼命的自己!

你可能感兴趣的:(Java)