详解Java阻塞队列(BlockingQueue)的四组API

什么是阻塞队列?

队列是我们常见的一种数据结构,特性就是FIFO(先进先出)。而阻塞队列,前面加了阻塞两个字,顾名思义就是对队列为空的时候,“取”操作会使队列block,“添加/存入”操作也会使队列block。 BlockingQueue是一个接口,我们所知道的实现类就有七个

                                                                

这里我们并不打算介绍这些实现类的特性,而是要介绍他们的四组共同API。

四组API

这里我们先用表格简单了解一下,下面再用实例代码来介绍。

方式 抛出异常 有返回值,不抛出异常 阻塞等待 超时等待
添加 add(e) offer(e) put(e) offer(e,time,unit)
移除 remove() poll() take() poll(time,unit)
检测队首元素 element() peek()

第一组

1、添加抛出异常
public class Demo01 {
    public static void main(String[] args) {
        // 构造方法参数:public ArrayBlockingQueue(int capacity, boolean fair)
        // 第一个参数:初始化阻塞队列的容量大小
        // 第二个参数:指定该阻塞队列是否为公平或不公平锁

        BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

        // 添加元素
        queue.add("a");
        queue.add("b");
        queue.add("c");
    }
}

运行结果:

2、移除抛出异常

public class Demo01 {
    public static void main(String[] args) {
        // 构造方法参数:public ArrayBlockingQueue(int capacity, boolean fair)
        // 第一个参数:初始化阻塞队列的容量大小
        // 第二个参数:指定该阻塞队列是否为公平或不公平锁

        BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

        // 添加元素
        System.out.println(queue.add("a"));
        System.out.println(queue.add("b"));

        // 移除元素
        queue.remove();
        queue.remove();
        queue.remove();
    }
}

运行结果:

第二组

1、添加有返回值

package com.lzp.blockqueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @Author LZP
 * @Date 2020/8/8 8:12
 * @Version 1.0
 *
 * 有返回值,且不抛出异常
 */
public class Demo02 {
    public static void main(String[] args) {
        // 创建阻塞队列对象
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);

        // 添加元素:若添加成功,则返回true,反之,则返回false
        System.out.println(queue.offer(1));
        System.out.println(queue.offer(2));
        System.out.println(queue.offer(3));
        System.out.println(queue.offer(4));
    }
}

运行结果:

2、移除有返回值

package com.lzp.blockqueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @Author LZP
 * @Date 2020/8/8 8:12
 * @Version 1.0
 *
 * 有返回值,且不抛出异常
 */
public class Demo02 {
    public static void main(String[] args) {
        // 创建阻塞队列对象
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);

        // 添加元素:若添加成功,则返回true,反之,则返回false
        System.out.println(queue.offer(1));
        System.out.println(queue.offer(2));
        System.out.println(queue.offer(3));
        System.out.println(queue.offer(4));

        // 移除元素:若移除成功,则返回移除的值,反之,则返回false
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
    }
}

运行结果:

第三组

1、添加时,如果队列已满,则阻塞等待

package com.lzp.blockqueue;

import java.util.Iterator;
import java.util.concurrent.*;

/**
 * @Author LZP
 * @Date 2020/8/8 8:28
 * @Version 1.0
 *
 * 阻塞等待,即一直等待,直到可以往队列里添加或移除元素为止
 *
 * 注意:普通队列只能从队首取第一个元素
 * 添加阻塞
 */
public class Demo03 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(4);

        // 开启一个线程先把队列里添满元素
        new Thread(() -> {
            System.out.println("-----" + Thread.currentThread().getName() + "正在往阻塞队列里添加元素------");
            try {
                for (int i = 1; i <= 4; i++) {
                    TimeUnit.SECONDS.sleep(1);
                    queue.put(i + "");
                    // element()方法,用来取队列的队首元素
                    System.out.println("-----成功添加第" + i + "个元素-----" + i);
                }
                System.out.println("-----" + Thread.currentThread().getName() + "添加元素完毕------");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 判断当前线程数,如果>2则一直等待,不能往下执行
        // 为了保证能将队列添满元素,再进行后续操作
        while ((Thread.activeCount() > 2)) {
        }

//        System.out.println("遍历开始");
//        Iterator<String> iterator = queue.iterator();
//        while (iterator.hasNext()) {
//            System.out.println(iterator.next());
//        }
//        System.out.println("遍历结束");

        // 此时开启一个线程去往队列里添加元素
        new Thread(() -> {
            try {
                System.out.println("-----" + Thread.currentThread().getName() + "开始添加元素------");
                String str = "李时珍的皮";
                queue.put(str);
                System.out.println("-----" + Thread.currentThread().getName() + "成功添加元素------" + str);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        TimeUnit.SECONDS.sleep(3);

//        // 移除元素
//        System.out.println(queue.take());

        // 让主线程等了3秒之后,然后派一个线程去移除元素

        new Thread(() -> {
            try {
                System.out.println("-----" + Thread.currentThread().getName() + "开始移除元素------");
                String str = queue.take();
                System.out.println(str);
                System.out.println("-----" + Thread.currentThread().getName() + "成功移除元素------" + str);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

运行结果:

2、移除元素时,如果队列已空,则阻塞等待

package com.lzp.blockqueue;

import java.util.Iterator;
import java.util.concurrent.*;

/**
 * @Author LZP
 * @Date 2020/8/8 8:28
 * @Version 1.0
 *
 * 阻塞等待,即一直等待,直到可以往队列里添加或移除元素为止
 *
 * 注意:普通队列只能从队首取第一个元素
 * 移除阻塞
 */
public class Demo03 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

        System.out.println("刚开始,队列里的元素:" + queue);

        // 开启一个线程去移除元素
        new Thread(() -> {
            try {
                System.out.println("开始移除时,队列里的元素:" + queue);
                System.out.println("正在移除元素:" + queue.take());
                System.out.println("移除完后,队列里的元素:" + queue);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        TimeUnit.SECONDS.sleep(3);

        // 等待3秒后,再开启一个线程去添加元素
        new Thread(() -> {
            try {
                // 添加元素
                queue.put("Hello");
                queue.put("World");
                System.out.println("添加完后,队列里的元素:" + queue);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

运行结果:

第四组

1、添加时,如果队列已满,则超时等待(即等待设置的时间过后就立马返回,不会一直阻塞下去)

package com.lzp.blockqueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author LZP
 * @Date 2021/2/28 10:24
 * @Version 1.0
 * <p>
 * 超时等待
 */
public class Demo04 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);

        // 先将队列填满
        for (int i = 1; i <= 3; i++) {
            String e = i + "";
            System.out.println("添加元素:" + e + "返回值为:" + queue.offer(e, 2, TimeUnit.SECONDS));
        }

        System.out.println("等2秒后");
        // 此时队列已满,再向队列中添加元素时,就会出现超时等待的情况
        System.out.println("返回值为:" + queue.offer(4 + "", 2, TimeUnit.SECONDS));
    }
}

运行结果:

2、移除时,如果队列已空,则超时等待(即等待设置的时间过后就立马返回,不会一直阻塞下去)

package com.lzp.blockqueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author LZP
 * @Date 2021/2/28 10:24
 * @Version 1.0
 * 超时等待 
 * 移除元素
 */
public class Demo04 {
    public static void main(String[] args) throws InterruptedException {
       
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);

        System.out.println("等2秒后");
        // 此时队列为空,移除时会发生超时阻塞,且返回null
        System.out.println("返回值为:" + queue.poll(2, TimeUnit.SECONDS));   
    }
}

运行结果:

posted @ 2021-02-28 09:02  没有你哪有我  阅读(574)  评论(0编辑  收藏  举报