线程小酌之java中的阻塞队列(代码片段)

tanyunlong_nice tanyunlong_nice     2022-12-13     682

关键词:

       最近在学习java中自带的JDK并发包,java.util.concurrent,发现功能很强大,其中之一就是工作中多次用到的线程工具类BlockingQueue。在实际开发工作和面试过程中,经常会考察对于该工具类的使用和理解。

1. 什么是阻塞队列?

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。

2.详解BlockingQueue


BlockingQueue最终会有四种状况,抛出异常、返回特殊值、阻塞、超时,下表总结了这些方法:


 抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e, time, unit)
移除remove()poll()take()poll(time, unit)
检查element()peek()不可用不可用


       BlockingQueue是个接口,有如下实现类:

       1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。

       2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。 

       3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。

       4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然。


由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。

package cn.thread;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 多线程模拟实现生产者/消费者模型
 *  
 */
public class BlockingQueueTest2 
    /**
     * 
     * 定义装苹果的篮子
     * 
     */
    public class Basket 
        // 篮子,能够容纳3个苹果
        BlockingQueue<String> basket = new LinkedBlockingQueue<String>(3);

        // 生产苹果,放入篮子
        public void produce() throws InterruptedException 
            // put方法放入一个苹果,若basket满了,等到basket有位置
            basket.put("An apple");
        

        // 消费苹果,从篮子中取走
        public String consume() throws InterruptedException 
            // take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部)
            return basket.take();
        
    

    // 定义苹果生产者
    class Producer implements Runnable 
        private String instance;
        private Basket basket;

        public Producer(String instance, Basket basket) 
            this.instance = instance;
            this.basket = basket;
        

        public void run() 
            try 
                while (true) 
                    // 生产苹果
                    System.out.println("生产者准备生产苹果:" + instance);
                    basket.produce();
                    System.out.println("!生产者生产苹果完毕:" + instance);
                    // 休眠300ms
                    Thread.sleep(300);
                
             catch (InterruptedException ex) 
                System.out.println("Producer Interrupted");
            
        
    

    // 定义苹果消费者
    class Consumer implements Runnable 
        private String instance;
        private Basket basket;

        public Consumer(String instance, Basket basket) 
            this.instance = instance;
            this.basket = basket;
        

        public void run() 
            try 
                while (true) 
                    // 消费苹果
                    System.out.println("消费者准备消费苹果:" + instance);
                    System.out.println(basket.consume());
                    System.out.println("!消费者消费苹果完毕:" + instance);
                    // 休眠1000ms
                    Thread.sleep(1000);
                
             catch (InterruptedException ex) 
                System.out.println("Consumer Interrupted");
            
        
    

    public static void main(String[] args) 
        BlockingQueueTest2 test = new BlockingQueueTest2();

        // 建立一个装苹果的篮子
        Basket basket = test.new Basket();

        ExecutorService service = Executors.newCachedThreadPool();
        Producer producer = test.new Producer("生产者001", basket);
        Producer producer2 = test.new Producer("生产者002", basket);
        Consumer consumer = test.new Consumer("消费者001", basket);
        service.submit(producer);
        service.submit(producer2);
        service.submit(consumer);
        // 程序运行5s后,所有任务停止
//        try 
//            Thread.sleep(1000 * 5);
//         catch (InterruptedException e) 
//            e.printStackTrace();
//        
//        service.shutdownNow();
    






线程小酌之理解线程池(代码片段)

...言    在学习JAVASE部分中,我们都学习到了基本的线程创建继承THREAD类或实现Runnable接口,在正常负载情况下,为每个任务分配一个线程这种方法能够提升串行执行的性能。只要请求的导弹速率不超出服务器的请求... 查看详情

juc并发编程共享模式之工具线程池--自定义线程池(阻塞队列)(代码片段)

1.自定义线程池(阻塞队列)1.1线程池介绍产生背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。解决思路:提前创建好多个线程,放入线程池中,使用时直... 查看详情

juc之阻塞队列解读(blockingqueue)(代码片段)

...ockingQueue简介Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。本文详细介绍了BlockingQue... 查看详情

线程池阻塞队列之arrayblockingqueue(代码片段)

ArrayBlockingQueue介绍ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列。线程安全是指,ArrayBlockingQueue内部通过“互斥锁”保护竞争资源,实现了多线程对竞争资源的互斥访问。有界是指,ArrayBlockingQueue对应的数组是有... 查看详情

java之阻塞队列深度剖析(代码片段)

阻塞队列1.什么是阻塞队列2.阻塞队列的代码使用3.生产者消费者模型(1)应用一:解耦合(2)应用二:削峰填谷(3)相关代码4.阻塞队列和生产者消费者模型功能的实现1.什么是阻塞队列阻塞队列... 查看详情

juc-多线程之阻塞队列blockingqueue(代码片段)

一、队列队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。和栈一样,队列是一种操作受限制的线性表,进行插入操作的端称为队尾,,进行删... 查看详情

java阻塞队列和线程池原理(代码片段)

...8;并非所有方式都阻塞)③阻塞队列简单使用【2】Java线程池一、我们为什么需要Java线程池?使用它的好处是什么?①降低资源消耗。②提高响应速度。③提高线程的可 查看详情

java中的线程--并发库中的集合(代码片段)

  线程中的知识点基本都已经学完了,看看Java5并发库中提供的集合。。。一、可堵塞队列队列包含固定长度的队列和不固定长度的队列ArrayBlockQueue中只有put()方法和take()方法才具有阻塞功能1、阻塞队列的功能和效果,代码如... 查看详情

并发队列之concurrentlinkedqueue(代码片段)

  本来想着直接说线程池的,不过在说线程池之前,我们必须要知道并发安全队列;因为一般情况下线程池中的线程数量是一定的,肯定不会超过某个阈值,那么当任务太多了的时候,我们必须把多余的任务保存到并发安全队... 查看详情

死磕java集合之concurrentlinkedqueue源码分析(代码片段)

...LinkedQueue如何保证并发安全?(3)ConcurrentLinkedQueue能用于线程池吗?简介ConcurrentLinkedQueue只实现了Queue接口,并没有实现BlockingQueue接口,所以它不是阻塞队列,也不能用于线程池中,但是它是线程安全的,可用于多线程环境中。... 查看详情

死磕java集合之concurrentlinkedqueue源码分析(代码片段)

...LinkedQueue如何保证并发安全?(3)ConcurrentLinkedQueue能用于线程池吗?简介ConcurrentLinkedQueue只实现了Queue接口,并没有实现BlockingQueue接口,所以它不是阻塞队列,也不能用于线程池中,但是它是线程安全的,可用于多线程环境中。... 查看详情

juc多线程:阻塞队列arrayblockingqueue与linkedblockingqueue(代码片段)

...加:当阻塞队列已满时,队列会阻塞加入元素的线程,直到队列元素不满时才重新唤醒线程执行加入元素操作。阻塞删除:但阻塞队列元素为空时,删除队列元素的线程将被阻塞,直到队列不为空再执行删... 查看详情

java并发多线程编程——阻塞队列(blockingqueue)(代码片段)

目录一、阻塞队列(BlockingQueue)的概述二、阻塞队列(BlockingQueue)的优点三、阻塞队列(BlockingQueue)的架构介绍四、阻塞队列(BlockingQueue)的分类五、阻塞队列(BlockingQueue)的核心方法5.... 查看详情

java实现阻塞队列简易线程池计时器(代码片段)

Java实现阻塞队列、线程池、计时器Java实现阻塞队列、简易线程池、计时器Java实现阻塞队列、简易线程池、计时器packagedemo0821;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.*;/***user:ypc;*date:2021-08-21 查看详情

java实现阻塞队列简易线程池计时器(代码片段)

Java实现阻塞队列、线程池、计时器Java实现阻塞队列、简易线程池、计时器Java实现阻塞队列、简易线程池、计时器packagedemo0821;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.*;/***user:ypc;*date:2021-08-21 查看详情

并发队列之arrayblockingqueue(代码片段)

...intcount;//独占锁finalReentrantLocklock;//如果数组中为空,还有线程取数据,就丢到这个条件变量中来阻塞privatefinalConditionnotEmpty;//队列满了,还有线程往数组中添加数据,就把线程丢到这里来阻塞privatefinalConditionnotFull;    ... 查看详情

源码角度了解阻塞队列之synchronousqueue(代码片段)

...步队列,它没有任何的容量,插入操作都必须等待另一个线程的相应删除操作从它的构造方法中我们可以看到,可以指定是否为公平的队列,如果是公平的使用队列,如果不是公平的,使用栈来存储put()方法publicvoidput(Ee)throwsInter... 查看详情

并发编程中的阻塞队列概述(代码片段)

...的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。2)支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。阻塞队列常用于生产者和消费者的场景,生产者是向队列里... 查看详情