Java阻塞队列——用法及常用场景

Java 阻塞队列

  • 入队阻塞:当队列已满时,尝试入队的线程会被阻塞,直到队列有空闲空间。
  • 出队阻塞:当队列为空时,尝试出队的线程会被阻塞,直到队列中有元素。
操作类型 抛出异常 返回特殊值 阻塞等待 超时等待
入队 add(e) offer(e) put(e) offer(e, timeout, unit)
出队 remove() poll() take() poll(timeout, unit)
查看队首 element() peek()
实现类 特点 适用场景
ArrayBlockingQueue 基于数组、有界、公平 / 非公平锁 固定容量的生产消费
LinkedBlockingQueue 基于链表、默认无界(Integer.MAX_VALUE) 任务队列(如线程池)
SynchronousQueue 无存储、入队必须等出队(一对一传递) 快速传递数据(如 Executors.newCachedThreadPool ())
DelayQueue 延迟队列、元素需实现 Delayed 接口 定时任务(如定时关闭连接)

阻塞队列用法

java 复制代码
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueDemo {
    // 定义有界阻塞队列,容量为3
    private static final BlockingQueue<String> QUEUE = new ArrayBlockingQueue<>(3);

    public static void main(String[] args) {
        // 1. 生产者线程:不断往队列放数据
        new Thread(() -> {
            try {
                int count = 1;
                while (true) {
                    String data = "武汉美食" + count++;
                    QUEUE.put(data); // 队列满时会阻塞
                    System.out.println("生产者放入:" + data + " | 队列当前大小:" + QUEUE.size());
                    Thread.sleep(500); // 模拟生产耗时
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 恢复中断状态
                System.out.println("生产者被中断");
            }
        }, "生产者").start();

        // 2. 消费者线程:不断从队列取数据
        new Thread(() -> {
            try {
                while (true) {
                    String data = QUEUE.take(); // 队列空时会阻塞
                    System.out.println("消费者取出:" + data + " | 队列当前大小:" + QUEUE.size());
                    Thread.sleep(1000); // 模拟消费耗时(比生产慢,队列会慢慢满)
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("消费者被中断");
            }
        }, "消费者").start();
    }
}

场景1 异步消息处理(生产者 - 消费者进阶)

比如电商系统中,用户下单后,主线程只负责保存订单,下单成功的通知、库存扣减等耗时操作,交给异步线程处理 ------ 用阻塞队列解耦主线程和异步线程。

java 复制代码
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.BlockingQueue;

// 订单实体
class Order {
    private String orderId;
    private String goodsName;

    public Order(String orderId, String goodsName) {
        this.orderId = orderId;
        this.goodsName = goodsName;
    }

    // getter
    public String getOrderId() { return orderId; }
    public String getGoodsName() { return goodsName; }
}

public class OrderMessageDemo {
    // 订单消息队列(指定容量100,避免无限堆积)
    private static final BlockingQueue<Order> ORDER_QUEUE = new LinkedBlockingQueue<>(100);

    // 初始化消费者线程(项目启动时启动)
    static {
        new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 阻塞等待新订单
                    Order order = ORDER_QUEUE.take();
                    // 处理异步逻辑:扣库存、发通知
                    handleOrderAsync(order);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("订单处理线程被中断");
                    break;
                }
            }
        }, "订单处理线程").start();
    }

    // 主线程:下单接口
    public static void createOrder(String orderId, String goodsName) {
        try {
            // 1. 保存订单(核心逻辑,快速完成)
            System.out.println("主线程:保存订单 " + orderId + " 成功");
            // 2. 放入阻塞队列,异步处理后续逻辑
            ORDER_QUEUE.put(new Order(orderId, goodsName));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("下单失败:队列阻塞被中断");
        }
    }

    // 异步处理订单的逻辑
    private static void handleOrderAsync(Order order) {
        System.out.println("异步线程:处理订单 " + order.getOrderId() 
                + ",扣减[" + order.getGoodsName() + "]库存,发送下单成功通知");
        // 模拟耗时操作
        try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    }

    // 测试
    public static void main(String[] args) {
        // 模拟用户下单(主线程快速响应)
        createOrder("O20260223001", "武汉热干面");
        createOrder("O20260223002", "周黑鸭");
        createOrder("O20260223003", "武昌鱼");

        // 等待异步线程处理完成
        try { Thread.sleep(2000); } catch (InterruptedException e) {}
    }
}
java 复制代码
主线程:保存订单 O20260223001 成功
主线程:保存订单 O20260223002 成功
主线程:保存订单 O20260223003 成功
异步线程:处理订单 O20260223001,扣减[武汉热干面]库存,发送下单成功通知
异步线程:处理订单 O20260223002,扣减[周黑鸭]库存,发送下单成功通知
异步线程:处理订单 O20260223003,扣减[武昌鱼]库存,发送下单成功通知

场景2 延迟队列(DelayQueue)------ 定时任务

比如:用户下单后 30 分钟未付款,自动取消订单;连接空闲 5 分钟后自动关闭。DelayQueue 可以实现这种 "延迟执行" 的需求,元素必须实现Delayed接口。

java 复制代码
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

// 延迟订单任务(实现Delayed接口)
class DelayOrderTask implements Delayed {
    private String orderId;
    // 任务执行的截止时间(毫秒)
    private long expireTime;

    public DelayOrderTask(String orderId, long delayTime, TimeUnit unit) {
        this.orderId = orderId;
        // 计算截止时间:当前时间 + 延迟时间
        this.expireTime = System.currentTimeMillis() + unit.toMillis(delayTime);
    }

    // 核心方法:返回剩余延迟时间(<=0时,队列会取出该元素)
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    // 排序用(DelayQueue是优先级队列)
    @Override
    public int compareTo(Delayed o) {
        return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
    }

    // 取消订单的逻辑
    public void cancelOrder() {
        System.out.println("定时任务:订单" + orderId + "超时未付款,自动取消");
    }
}

public class DelayQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue<DelayOrderTask> delayQueue = new DelayQueue<>();

        // 1. 添加延迟任务:3秒后取消订单O001,1秒后取消订单O002
        delayQueue.put(new DelayOrderTask("O001", 3, TimeUnit.SECONDS));
        delayQueue.put(new DelayOrderTask("O002", 1, TimeUnit.SECONDS));

        System.out.println("添加延迟任务完成,等待执行...");

        // 2. 消费延迟队列(线程中循环执行)
        new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 阻塞等待:直到有任务到期
                    DelayOrderTask task = delayQueue.take();
                    task.cancelOrder(); // 执行取消订单逻辑
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();

        // 等待任务执行完成
        Thread.sleep(4000);
    }
}
java 复制代码
添加延迟任务完成,等待执行...
定时任务:订单O002超时未付款,自动取消
定时任务:订单O001超时未付款,自动取消
相关推荐
yy.y--2 小时前
Java多线程实例:输出线程名20次
java·开发语言
m0_528749002 小时前
MySQL CAPI核心操作全解析
数据库·mysql
Apple_羊先森2 小时前
ORACLE数据库巡检SQL脚本--23、检查Oracle数据库中被锁定的数据库对象
数据库·sql·oracle
时光书签2 小时前
数据库服务器磁盘存储扩容
数据库
—Miss. Z—2 小时前
计算机软件资格考试—第六章 数据库基础知识
数据库
SakitamaX2 小时前
Tomcat介绍与实验
java·tomcat
消失的旧时光-19432 小时前
C++ 多线程与并发系统取向(七)—— 并发排障与工程纪律(从“会写”到“能控场”)
开发语言·c++·并发
Y001112362 小时前
Day24—IO流-2
java·开发语言