【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

JDK 17 安装与配置指南(图文详解)

JDK 17 安装与配置指南(图文详解)

1. 开篇简介——长期支持与现代化Java开发 1.1 为什么选择JDK 17         JDK 17(Java Development Kit 17)是Oracle在2021年9月发布的长期支持版本(LTS, Long-Term Support),这意味着它将获得至少8年的官方维护与安全更新,直到2029年甚至更久。对于企业级应用和开发者来说,LTS版本意味着更高的稳定性、安全性和长期可维护性,使其成为生产环境的理想选择。         相较于非LTS版本(如JDK 18、19等),JDK 17不仅提供了关键的安全补丁和性能优化,还引入了许多现代化语言特性和API增强,帮助开发者编写更简洁、更高效的代码。         目前SpringBoot的最低支持版本是jdk17 1.2 适用人群 * Java初学者:JDK 17 提供了更直观、更现代化的语法,降低了学习门槛。 * 需要升级环境的开发者:从JDK 8/11迁移?JDK 17 是当前最稳定、最先进的LTS版本。

By Ne0inhk
Java初识面向对象+类与对象+封装核心

Java初识面向对象+类与对象+封装核心

🏠个人主页:黎雁 🎬作者简介:C/C++/JAVA后端开发学习者 ❄️个人专栏:C语言、数据结构(C语言)、EasyX、JAVA、游戏、规划、程序人生 ✨ 从来绝巘须孤往,万里同尘即玉京 文章目录 * ✨Java面向对象精讲(一):初识面向对象+类与对象+封装核心|零基础吃透OOP思想 * 📌 文章摘要(248字) * 🕒 阅读时长:约12分钟 * ✅ 适用人群 & 阅读重点 * 📖 知识回顾(课前必看,快速衔接) * 一、初识面向对象 ☀️ 从生活到代码,彻底理解核心思想 * 1.1 什么是面向对象?(生活案例,通俗易懂) * 1.2 我们要学的两大核心内容 * 二、设计对象并使用 ✍️ 类与对象【核心重点,

By Ne0inhk
将openclaw接入飞书:10分钟,让你的AI员工直接操作你的文档和表格!

将openclaw接入飞书:10分钟,让你的AI员工直接操作你的文档和表格!

上一篇,我们给小龙虾接了 Telegram,实现了手机遥控。 但说实话,Telegram 只解决了"能聊天"的问题。你跟小龙虾说"帮我写个文档",它写完了——然后呢?你还得自己复制粘贴到你的编辑器中。 这就像请了个助手,他只能站在门外隔着门跟你喊话,但不能进屋帮你干活。 今天这篇,我们把门打开。让小龙虾直接进入你的飞书——读文档、写文档、操作表格、管理日程,全部自己来。 先看效果👇 飞书的配置比 Telegram 多一些步骤,但别慌——跟着我走,每一步都有截图,大概10分钟搞定。 飞书的接入分四个阶段,先有个全局概念,不容易迷路: 1. 在飞书上造一个机器人 — 相当于给小龙虾办一张飞书工牌 2. 在服务器上装飞书插件 — 让小龙虾学会"说飞书的语言" 3.

By Ne0inhk
深入浅出Java Condition 的await和signal机制(一)

深入浅出Java Condition 的await和signal机制(一)

每个对象都可以调用 Object 的 wait/notify 方法来实现等待/通知机制。而 Condition 接口也提供了类似的方法。Condition 接口一共提供了以下 7 个方法: * await():线程等待直到被通知或者中断。类似于 Object.wait()。 * awaitUninterruptibly():线程等待直到被通知,即使在等待时被中断也不会返回。没有与之对应的 Object 方法。 * await(long time, TimeUnit unit):线程等待指定的时间,或被通知,或被中断。类似于 Object.wait(long timeout),但提供了更灵活的时间单位。 * awaitNanos(long nanosTimeout):线程等待指定的纳秒时间,或被通知,或被中断。没有与之对应的 Object 方法。 * awaitUntil(Date

By Ne0inhk