• 阻塞队列BlockingQueue


    阻塞队列是Java5的内容,定义了阻塞队列的接口java.util.concurrent.BlockingQueue,
    阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,
    直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止

    java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,
    它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue
    接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。不需要担心等待生产者
    有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。
    Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、
    PriorityBlockingQueue,、SynchronousQueue等。

    抛出异常(操作无法立即执行则抛出异常)特殊值(操作无法立即执行则返回一个特定值true / false) 阻塞 超时 
    插入add(e)在添加元素的时候,若超出了阻塞队列的长度会直接抛出异常offer(e)如果发现队列已满无法添加的话,会直接返回falseput(e)添加元素时发现队列已经满了会发生阻塞一直等待空间,以加入元素offer(e,time,unit)
    移除remove()若队列为空抛出NoSuchElementException异常poll()若队列为空,返回null take()若队列为空,发生阻塞,等待有元素    poll(time,unit) 
    检查 element()                                                 peek()   

    阻塞队列与平常接触的普通队列LinkedList或ArrayList等的最大不同点,在于阻塞队列支出阻塞添加和阻塞删除方法。
    - 阻塞添加:所谓的阻塞添加是指当阻塞队列元素已满时,队列会阻塞加入元素的线程,直队列元素不满时才重新唤醒线程执行元素加入操作
    - 阻塞删除:阻塞删除是指在队列元素为空时,删除队列元素的线程将被阻塞,直到队列不为空再执行删除操作(一般都会返回被删除的元素)

    BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。
    JAVA并发包提供三个常用的并发队列实现,分别是:ConcurrentLinkedQueue、LinkedBlockingQueue和ArrayBlockingQueue。

    使用阻塞队列实现的生产者消费者模式

    阻塞的实现是依赖于阻塞队列实现的,put/take

    1. public class Producer extends Thread{
    2. private BlockingQueue queue;
    3. public Producer(BlockingQueue queue){
    4. this.queue=queue;
    5. }
    6. public void run(){
    7. Random r=new Random();
    8. while(true){
    9. try{
    10. String temp="str_"+r.nextInt();
    11. queue.put(temp); //put方法会阻塞
    12. System.out.println("生产"+temp);
    13. Thread.sleep(20);
    14. } catch(InterruptedException e){
    15. e.printStackTrace();
    16. }
    17. }
    18. }
    19. }
    20. public class Consumer extends Thread{
    21. private BlockingQueue queue;
    22. public Producer(BlockingQueue queue){
    23. this.queue=queue;
    24. }
    25. public void run(){
    26. while(true){
    27. try{
    28. String temp=queue.take(); //take会阻塞
    29. System.out.println("消费"+temp);
    30. Thread.sleep(10);
    31. } catch(InterruptedException e){
    32. e.printStackTrace();
    33. }
    34. }
    35. }
    36. }

    测试类

    1. BlockingQueue queue=new ArrayBlockingQueue<>(3);
    2. new Producer(queue).start();
    3. new Thread(new Consumer(queue)).start();

    BlockingQueue接口定义了一种阻塞的FIFO queue,每一个BlockingQueue都有一个容量,
    让容量满时往BlockingQueue中添加数据时会造成阻塞,当容量为空时取元素操作会阻塞
    - ArrayBlockingQueue是初始容器固定的阻塞队列,可以用来作为数据库模块成功竞拍的队
    列,比如有10个商品,那么就设定一个10大小的数组队列。ArrayBlockingQueue的内部是通
    过一个可重入锁ReentrantLock和两个Condition条件对象来实现阻塞
    - LinkedBlockingQueue是一个阻塞的线程安全的队列,底层采用链表实现,入队和出队都
    用了加锁,当队空的时候线程会暂时阻塞;它如果不指定容量,默认为Integer.MAX_VALUE,也就是无界队列。所以为了避免队列过大造成机器负载或者内存爆满的情况出现,我们在使用的时候建议手动传一个队列的大小。
    - put方法:1、队列已满,阻塞等待。2、队列未满,创建一个node节点放入队列中,如果放
    完以后队列还有剩余空间,继续唤醒下一个添加线程进行添加。如果放之前队列中没有元素,放完以后要唤醒消费线程进行消费
    - take方法:1、队列为空,阻塞等待。2、队列不为空,从队首获取并移除一个元素,如果消
    费后还有元素在队列中,继续唤醒下一个消费线程进行元素移除。如果放之前队列是满元素的情况,移除完后要唤醒生产线程进行添加元素。
    ConcurrentLinkedQueue是一个基于链表的无界非阻塞队列,并且是线程安全的,它采用的是先进先出的规则,当我们增加一个元素时,它会添加到队列的末尾,当我们取一个元素时,它会返回一个队列头部的元素。不使用锁而是使用的是CAS原语无锁队列实现,是一个异步队列,入队速度很快,出队进行了加锁,性能稍慢;当多个线程共享访问一个公共collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素

  • 相关阅读:
    图数据库Neo4J 中文分词查询及全文检索(建立全文索引)
    Redis 持久化机制
    5. RxJava合并条件操作符
    Pyspark案例综合(数据计算)
    java毕业设计成品基于SpringBoot美容院预约管理系统
    DataSheet专业名词解读——每天10个专业名词(1)23.9.18 (NXP)MPC5604B/C
    cmake使用
    (八)MyBatis中参数的处理
    金融外包测试项目经验分享
    After Effects 2023 v23.6
  • 原文地址:https://blog.csdn.net/qq_51222096/article/details/126897190