BlockingQueue阻塞队列获取元素4种处理方案

什么情况下我们会使用阻塞队列:多线程并发处理,线程池!

 阻塞队列 4种解决方案

方式抛出异常不抛异常,有返回值阻塞等待超时等待
添加addofferput()offer (Timeout)
移除removepolltake()poll (Timeout)
检测队首元素element()peek()//

1. 抛出异常

/**
  抛出异常
  add:超出队列指定容量,会报:Queue full 异常
  remove:(每调用一次,移除一个元素),队列值为空时继续remove会报:NoSuchElementException
*/
public static void main(String[] args){
    ArrayBlockingQueue queue = new ArrayBlockingQueue<>(2);
  
    System.out.println(queue.add("1"));
    System.out.println(queue.add("2"));
    //queue.add("3"); // 使用add超出队列指定容量,会报:Queue full异常

    // 获取队列首部元素 :1
    System.out.println(queue.element());

    System.out.println("移除元素:"+queue.remove());//队列为空用移除:NoSuchElementException
    System.out.println("队列:"+queue);
}

执行结果:

把 queue.add("3"); 注释打开:添加第3个元素时,报Queue full异常

 

2. 不抛异常,有返回值

/**
    有返回值,没有异常
    offer:返回false,超出容量后不再添加入队
    poll:(每调用一次,移除一个元素)队列值为空时继续poll会输出null
*/
public static void main(String[] args){
    ArrayBlockingQueue queue = new ArrayBlockingQueue<>(2);
  
    System.out.println(queue.offer("3"));
    System.out.println(queue.offer("4"));
    System.out.println(queue.offer("5")); // false 超出容量后不再添加入队

    // 获取队列首部元素 :3
    System.out.println(queue.peek());

    System.out.println("移除元素:"+queue.poll());
    System.out.println("移除元素:"+queue.poll());
    System.out.println("移除元素: "+queue.poll()); // 队列值为空时继续poll会输出null
    System.out.println("队列:"+queue);

}

执行结果:1. 队列已满,继续offer返回false    2. 空队列poll 返回null

 

3. 阻塞等待

/**
  等待,阻塞(一直等待)
  put/take:超出长度无法添加,等待阻塞 / 队列内没有元素,等待阻塞
  ———— 直到添加成功或删除成功,程序才会结束
*/
public static void main(String[] args) throws InterruptedException {
    ArrayBlockingQueue queue = new ArrayBlockingQueue<>(2);
  
    queue.put("a");
    queue.put("b");
    //queue.put("c"); // 等待阻塞,直到添加成功,程序才会结束

    System.out.println("移除元素:"+queue.take());
    System.out.println("移除元素:"+queue.take());
    System.out.println("移除元素:"+queue.take()); // 等待阻塞,直到队内有元素可删除,程序才结束
    System.out.println("队列:"+queue);
}

执行结果:

 

4. 超时等待

/**
  等待,阻塞(超时等待)
  offer/poll:超出指定时间,还未操作成功,则忽略此次添加/删除
*/
public static void main(String[] args) throws InterruptedException {
    ArrayBlockingQueue queue = new ArrayBlockingQueue<>(2);

    queue.offer("A");
    queue.offer("B");
    queue.offer("C",2, TimeUnit.SECONDS); // 超时2秒后,还未添加成功,则忽略此次add

    System.out.println("移除元素:"+queue.poll());
    System.out.println("移除元素:"+queue.poll());
    System.out.println("移除元素: "+queue.poll(2, TimeUnit.SECONDS)); // 同offer
    System.out.println("队列:"+queue);
}

执行结果:2秒后添加失败 或 无元素可删除,则忽略,继续执行下列代码

 

扩展

/ArrayBlockingQueueLinkedBlockingQueue
阻塞实现方式通知模式实现通知模式实现
是否有界有界,必须指定初始化大小有界,构造器可以不初始化,默认为INTEGER.MAX_VALUE
存取元素是否会创建和销毁不会
生产者消费者锁的使用情况使用一把锁各自使用不同的锁

ArrayBlockingQueue 数组队列

基于数组实现的阻塞队列,创建对象时必须指定容量大小,且可指定是否公平(默认非公平,即不保证等待时间最长的队列最优先能够访问队列),存取元素的阻塞方法put/take,使用通知模式来实现。生产者和消费者存取数据用的同一把重入锁,无法真正实现生产者和消费者的并行

LinkedBlockingQueue 链表队列

基于链表实现,创建时如不指定大小,默认为Integet.MAX_VALUE,如果生产者的速度远大于消费者速度,则链表会堆积请问,造成内存压力,易产生OOM,其次是基于链表,每次放入元素会构造一个新节点对象,大量并发下可能会对GC造成一定影响。同样使用通知模式来实现,生产者和消费者分别使用两把重入锁实现同步,提高系统并发度

SynchronousQueue同步队列

特殊的阻塞队列,容量为0,也无法设置容量大小。put了一个元素,必须等待消费者线程take取出来,才能再进行下一个元素的插入操作

类似一个中介,从生产者手中拿到任务直接转交给消费者,直接传递机制,而非存储元素

public static void main(String[] args) {
        // 1.初始化同步队列
        BlockingQueue<String> queue = new SynchronousQueue<String>();

       // 2.定义2个线程,一个线程存,一个线程取
        new Thread(()->{
            try {
                // 添加3个元素
                System.out.println(Thread.currentThread().getName()+":put 1");
                queue.put("1");

                System.out.println(Thread.currentThread().getName()+":put 2");
                queue.put("2");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程A").start();

        new Thread(()->{
            try {
                // 每隔3秒取出一个元素
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+queue.take());

                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+queue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程B").start();
}

执行结果:put一个元素,须等待消费者线程取出来,下一个元素才能put进去

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值