可行,但需主动构造优先级队列:必须用PriorityBlockingQueue替换默认FIFO队列,任务需封装为可比较的PriorityTask并用序列号防堆不稳定,否则高优任务可能导致低优任务饿死。
可行,但需主动构造,不能依赖默认机制。
默认线程池不支持优先级是设计使然
ThreadPoolExecutor 默认使用 LinkedBlockingQueue 或 ArrayBlockingQueue,它们是严格 FIFO 队列。任务一旦入队,顺序就被固化,线程总是从队首取任务——无论这个任务是高优还是低优,只要它排在前面,就会先执行。
这不是缺陷,而是简化设计的结果:FIFO 保证可预测性、降低实现复杂度,适合大多数通用场景。
PriorityBlockingQueue 是核心支撑组件
要启用优先级调度,必须替换工作队列为 PriorityBlockingQueue,并确保其中的任务对象具备可比性:
立即学习“Java免费学习笔记(深入)”;
- 该队列基于堆结构,插入和取任务时自动维持优先级顺序(默认最小堆,priority 值越小越靠前)
- 它本身不定义比较逻辑,依赖元素实现 Comparable,或构造时传入 Comparator
- 队列无界,若高优任务持续涌入而消费滞后,可能引发内存溢出,需配合限流或拒绝策略
任务必须封装并固化优先级
普通 Runnable 或 Callable 不可排序,直接提交无效。必须包装成可比较类型:
- 定义包装类(如 PriorityTask),持有一个 final int priority 字段
- 实现 Comparable,compareTo 方法只比较 priority 字段,避免调用外部方法或读取可变状态
- 相同 priority 时,引入单调递增序列号(如 AtomicInteger),防止 compareTo 返回 0 导致堆结构不稳定
高优任务可能饿死低优任务
这是优先队列的固有行为,不是 bug:
- 只要不断有高优任务提交,队列头部永远被占据,低优任务可能无限等待
- Java 线程池不提供“公平轮询”“时间片配额”等保障机制
- 缓解方式包括:用 Semaphore 控制高优任务提交速率;在 Comparator 中加入时间衰减因子(如 (priority * 1000) - System.nanoTime()),让老任务随时间自动升权