JUC并发编程学习笔记(九)阻塞队列

阻塞队列

阻塞
队列

队列的特性:FIFO(fist inpupt fist output)先进先出

不得不阻塞的情况

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

学会使用队列

添加、移除

四组API

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

1、抛出异常

java 复制代码
public static void test01(){
    //队列是有大小的,创建时要明确该队列最大能有几个元素
    BlockingQueue queue = new ArrayBlockingQueue<>(3);
    //当你添加的元素超出队列规定的最大元素量时,抛出异常java.lang.IllegalStateException: Queue full
    System.out.println(queue.add("A"));
    System.out.println(queue.add("B"));
    System.out.println(queue.add("C"));
    //当你移除的元素超出队列中含有的元素量时,抛出异常java.util.NoSuchElementException
    System.out.println(queue.element());
    System.out.println(queue.remove());
    System.out.println(queue.element());
    System.out.println(queue.remove());
    System.out.println(queue.element());
    System.out.println(queue.remove());


    System.out.println(queue.add("D"));
}

2、不抛出异常

java 复制代码
public static void test02(){
    //队列是有大小的,创建时要明确该队列最大能有几个元素
    BlockingQueue queue = new ArrayBlockingQueue<>(3);
    //当你添加的元素超出队列规定的最大元素量时,不抛出异常,通过返回的boolean值为false来表明
    System.out.println(queue.offer("A"));
    System.out.println(queue.offer("B"));
    System.out.println(queue.offer("C"));
    //当你移除的元素超出队列中含有的元素量时,不抛出异常,返回null来提示队列已经没有元素可以弹出了
    System.out.println(queue.peek());
    System.out.println(queue.poll());
    System.out.println(queue.peek());
    System.out.println(queue.poll());
    System.out.println(queue.peek());
    System.out.println(queue.poll());


    System.out.println(queue.offer("D"));
}

3、阻塞等待

java 复制代码
    public static void test03() throws InterruptedException {
        //队列是有大小的,创建时要明确该队列最大能有几个元素
        BlockingQueue queue = new ArrayBlockingQueue<>(3);

        queue.put("a");
        queue.put("b");
        queue.put("c");
        //当队列被元素占满后再进行添加,会一直阻塞等待,知道该元素加入队列
//        queue.put("c");
        System.out.println(queue.take());
        System.out.println(queue.take());
        System.out.println(queue.take());
        //当队列中没有元素时还去取,也会一直阻塞等待
//        System.out.println(queue.take());

    }

4、超时等待

java 复制代码
public static void test04() throws Exception{
    //队列是有大小的,创建时要明确该队列最大能有几个元素
    BlockingQueue queue = new ArrayBlockingQueue<>(3);
    System.out.println(queue.offer("a"));
    System.out.println(queue.offer("b"));
    System.out.println(queue.offer("c"));
    //当队列被占满时,设置超时等待,超过两秒就不等了,进不去就不进了
    System.out.println(queue.offer("d", 2, TimeUnit.SECONDS));
    System.out.println(queue.poll());
    System.out.println(queue.poll());
    System.out.println(queue.poll());
    //当队列元素为空时,设置超时等待,超过两秒就不等了,拿不到就不拿了
    System.out.println(queue.poll(2, TimeUnit.SECONDS));
}

SynchronousQueue

同步队列:同步队列每次插入操作都必须等待另一个线程执行相应的删除操作,反之亦然。同步队列没有容量,也就意味着只有当一个元素弹出后才能再进入一个元素,只能同时有一个元素。

存取:put、take

java 复制代码
package org.example.qu;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

public class SynchronousQueueDemo {
    public static void main(String[] args) {
        SynchronousQueue<String> synchroQueue = new SynchronousQueue<String>();

        new Thread(() -> {
            try {
                //直接在队列中存入三个元素
                System.out.println(Thread.currentThread().getName() + ": put 1");
                synchroQueue.put("1");
                System.out.println(Thread.currentThread().getName() + ": put 2");
                synchroQueue.put("2");
                System.out.println(Thread.currentThread().getName() + ": put 3");
                synchroQueue.put("3");


            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "T1").start();
        new Thread(() -> {
            try {
                //每次取之间延迟三秒
                TimeUnit.SECONDS.sleep(3);
                System.out.println(synchroQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(synchroQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(synchroQueue.take());

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "T2").start();

    }
}

我们通过结果发现,将要存入的元素会等待已经被存入的元素取出后才会存入,延迟三秒取出时,将要存入的元素也在等待三秒取出后再存入,这就是所谓的同步队列每次插入操作都必须等待另一个线程执行相应的删除操作,反之亦然。

同步队列和其它BlockingQueue不一样,他不存储元素,你put了一个值必须take取出,否则不能再put进去元素。

相关推荐
Wang's Blog4 小时前
Java 项目实战: 交友项目 - Dubbo 的内部结构与一次调用的完整链路
java·dubbo
Wang's Blog4 小时前
Java 项目实战: 交友项目 - Dubbo 入门引导
java·dubbo·交友
蜗牛互联网5 小时前
Python Agent工具调用的白名单、参数校验与审批门禁
java·服务器·前端·人工智能·后端·python
SL_staff5 小时前
当规则引擎开始‘懂业务’:JVS-Rules金融风控四大原生能力拆解
java·python·全栈
Shaoshing5 小时前
前缀和与差分
java·数据结构·算法·前缀和·差分
dd聊技术5 小时前
Prompt 从代码常量搬进数据库:改一句话,不用再发一次版
java·后端
ly76896 小时前
Spring Data MongoDB 批量写入实践:BulkOperations 批大小与写关注权衡
java·mongodb·spring·批量写入·bulkoperations·写关注·mongotemplate
TAKETODAY6 小时前
Netty 是怎么把 HTTP 请求交给 MVC 的?一个请求的完整链路
java·netty
蚰蜒螟6 小时前
从内核启动到 Java NIO:一次 socket accept 的源码串联之旅
java·python·nio
会编程的吕洞宾6 小时前
Spring AI 2.0 自校正结构化输出实战:让大模型稳定吐出合格 JSON
java·人工智能·后端·spring