【Java 开发日记】阻塞队列有哪些?拒绝策略有哪些?

【Java 开发日记】阻塞队列有哪些?拒绝策略有哪些?

目录

阻塞队列有哪些?

拒绝策略有哪些?

面试回答


阻塞队列有哪些?

在Java的java.util.concurrent包里面,阻塞队列的实现挺多的,我们可以根据它的功能和结构来记,主要分这么几类:

1. 按容量划分:

  • 有界队列: 就是队列有固定的容量。
    • ArrayBlockingQueue 最经典的一个,底层是数组,创建时必须指定大小。它的生产和消费用同一把锁,性能相对稳定。
    • LinkedBlockingQueue 底层是链表,它既可以是有界的(构造时指定容量),也可以默认是无界的(默认是Integer.MAX_VALUE,几乎相当于无界)。它的生产和消费用了两把锁,在高并发场景下吞吐量通常比ArrayBlockingQueue更高。
  • 无界队列: 理论上是无限的,只要内存够就能一直放。
    • PriorityBlockingQueue 一个支持优先级排序的无界队列。元素必须实现Comparable接口,或者构造时传入Comparator。它出队的顺序是按优先级来的,不是先进先出
    • DelayQueue 一个很特殊的队列,里面放的是实现了Delayed接口的元素。每个元素都有个到期时间,只有到期了的元素才能被取出来。典型应用就是做缓存过期、定时任务调度。

2. 特殊功能的队列:

  • SynchronousQueue 这个队列非常特别,它不存储元素。每一个put操作必须等待一个take操作,就像“手递手”交接一样。它直接传递任务,效率很高,常用于线程池之间直接传递工作。CachedThreadPool用的就是它。
  • LinkedTransferQueueLinkedBlockingQueueSynchronousQueue的结合体。它多了个transfer方法,如果当前有消费者在等待,就直接把元素给消费者;如果没有,就入队,并且会阻塞直到该元素被消费掉。性能很好。


所以,我比较常记的是ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueueDelayQueueSynchronousQueue这几个,它们各有各的应用场景。

拒绝策略有哪些?

拒绝策略是线程池的一个组成部分。当线程池的工作队列满了,并且所有线程也都达到最大线程数了,这时候再来新任务,就会触发拒绝策略。Java在ThreadPoolExecutor类里提供了4种内置的策略,都实现了RejectedExecutionHandler接口:

1. AbortPolicy(中止策略 - 默认策略):

  • 做法: 直接抛出一个RejectedExecutionException异常。
  • 感受: “比较粗暴,但好处是能让我们及时感知到系统出了饱和问题。”

2. CallerRunsPolicy(调用者运行策略):

  • 做法: 不抛弃任务,也不抛异常,而是将任务回退给调用者(提交任务的线程),让调用者自己去执行这个任务。
  • 感受: “这是一种‘负反馈’机制。提交任务的线程突然要自己去干活,它就忙起来了,自然就慢下来提交新任务了,给了线程池一个喘息的机会。这个策略在生产环境挺实用的,能平滑地降低流量。”

3. DiscardPolicy(丢弃策略):

  • 做法: 默默地把新提交的任务丢弃掉,不执行,也不给任何通知。
  • 感受: “风险比较大,因为任务丢了我们都不知道。除非是一些无关紧要的场景,否则一般不推荐。”

4. DiscardOldestPolicy(丢弃最老策略):

  • 做法:工作队列里排队时间最长的那个任务(队头的任务)丢掉,然后尝试把新任务再放进队列。
  • 感受: 这个策略有点‘喜新厌旧’。它可能丢弃掉一个非常重要的老任务,风险也挺高的,用的时候得想清楚业务上能不能接受。


当然,如果这四种都不满足需求,我们还可以自己实现RejectedExecutionHandler接口,来自定义拒绝策略,比如把拒绝的任务持久化到磁盘,或者记录日志后发个告警等等。

面试回答

Java中的阻塞队列主要有像ArrayBlockingQueue这种基于数组的有界队列,也有LinkedBlockingQueue这种基于链表可以无界的队列。还有一些特殊用途的,比如按优先级出队的PriorityBlockingQueue,做延时任务的DelayQueue,以及不存元素专门做传递的SynchronousQueue
 

关于拒绝策略,是线程池满载后的处理方式。默认的AbortPolicy会直接抛异常;CallerRunsPolicy会让提交任务的线程自己去执行,这个我们项目在用,能平滑流量;还有两种是直接丢弃任务或者丢弃队列中最老的任务。如果都不行,我们也可以根据业务自己实现一个。

如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!

Read more

【YF技术周报 Vol.01】OpenAI 国会指控 DeepSeek,字节发布 Seedance 2.0,Java 26 预览版来了

【YF技术周报 Vol.01】OpenAI 国会指控 DeepSeek,字节发布 Seedance 2.0,Java 26 预览版来了

🍃 予枫:个人主页 📚 个人专栏: 《Java 从入门到起飞》《读研码农的干货日常》 💻 Debug 这个世界,Return 更好的自己! 文章目录 * 🚨 1. OpenAI 向美国国会提交备忘录:指控 DeepSeek “非法蒸馏” * 🎬 2. 字节跳动发布 Seedance 2.0:对标 Sora 的视频生成模型 * 🛑 3. OpenAI 正式下线 GPT-4o,全面转向 GPT-5 * ☕ 4. Azul 发布《2026 Java 现状报告》:AI 开发中的 Java 渗透率攀升 * 💡 YF 的深度思考:护城河与工具链 👋 卷首语 大家好,我是予枫。 这是 《YF 技术周报》

By Ne0inhk

2025 最新 Claude Code 教程:从安装部署到 SpringBoot 项目实战(附完整 Java 示例)

前言 Claude Code 是 Anthropic 推出的 AI 编码助手,专为开发者打造,相比通用 AI,它对 Java、SpringBoot 等企业级开发场景的适配性更强,能精准生成可运行的代码、排查业务逻辑 bug、优化接口性能,大幅提升开发效率。本文从安装部署、提示词技巧、SpringBoot 项目实战三个核心维度,手把手教你玩转 Claude Code,最终实现 “AI 辅助完成完整 SpringBoot 项目开发并落地本地”。 一、Claude Code 安装部署(3 种主流方式) Claude Code 支持网页版、桌面客户端、IDE 插件三种使用形式,开发者优先推荐 IDE 插件(无缝融入本地开发流程)。 1. 环境前置要求

By Ne0inhk
虚拟线程(Virtual Threads)使用指南(Java 21+)

虚拟线程(Virtual Threads)使用指南(Java 21+)

虚拟线程是 Java 21 正式引入的轻量级用户态线程,核心优势是低开销、高并发、支持同步编程模型实现异步性能。下面将从前提准备、基础用法、进阶用法、实战场景、注意事项五个方面详细讲解具体使用方式。 一、使用前提 1. Java 版本要求:必须使用 Java 21 及以上版本(Java 19/20 为预览特性,需通过--enable-preview启用,不推荐生产环境使用)。 编译运行说明:若使用 Java 19/20(预览版),编译和运行时需添加--enable-preview参数: # 编译 javac --enable-preview -source 20 VirtualThreadDemo.java # 运行 java --enable-preview VirtualThreadDemo 环境验证:通过以下命令验证 Java 版本,确保满足要求:

By Ne0inhk
数据结构(Java版)第五期:ArrayList与顺序表(下)

数据结构(Java版)第五期:ArrayList与顺序表(下)

目录 一、用数组实现顺序表 一、用数组实现顺序表      我们提到过,顺序表是基于数组的封装,这次我们以int为例,用数组去实现一个顺序表。 public class MyArrayList { private int[] arr; public MyArrayList(int capacity){//指定初始容量 arr = new int[capacity];//这个顺序表依然是空的,还得使用add往里面添加有效元素 } }       既然存在有效与无效,那我们该如何区分呢?我们可以定义一个size变量。 private int size;//规定前size个元素为有效元素 下面就是进行写出方法,比如增、删、查、改等。 //获取元素个数 public int size(){ return size; } //新增元素,尾插 public void add(int

By Ne0inhk