Java 中基于优先级执行任务的线程池实现

在日常开发中,我们经常遇到这样一种需求:需要按照任务的优先级顺序来执行,而不是简单的先进先出(FIFO)。Java 提供了 PriorityBlockingQueue,这是一个基于优先级排序的线程安全队列,可以用于实现一个支持优先级任务的线程池。在这篇博客中,我们将介绍两种使用 PriorityBlockingQueue 实现优先级线程池的方法,并讨论它们的适用场景和优缺点。

方法一:实现 Comparable 接口的优先级任务类

1.1 方案概述

这种方法的核心在于让任务类(Task)实现 Comparable 接口,并在 compareTo 方法中定义优先级的排序逻辑。PriorityBlockingQueue 会根据 Comparable 的实现来自动对任务进行排序,优先级高的任务会被排在队列的前面,先执行。

1.2 实现步骤

  1. 定义优先级任务类:实现 RunnableCallable 接口,同时实现 Comparable 接口。
  2. 创建优先级线程池:使用 PriorityBlockingQueue 作为任务队列。
  3. 提交任务到线程池:按不同优先级提交任务,线程池会自动按照优先级来执行任务。

1.3 示例代码

import java.util.concurrent.*;public class PriorityTask implements Runnable, Comparable<PriorityTask> {private final int priority;private final String name;public PriorityTask(int priority, String name) {this.priority = priority;this.name = name;}@Overridepublic void run() {System.out.println("Executing task: " + name + " with priority: " + priority);}@Overridepublic int compareTo(PriorityTask other) {return Integer.compare(this.priority, other.priority); // 优先级值越小,优先级越高}
}public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new PriorityBlockingQueue<Runnable>());}
}

1.4 使用示例

public class Main {public static void main(String[] args) {PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(2, 4, 1, TimeUnit.MINUTES);executor.execute(new PriorityTask(10, "Low priority task"));executor.execute(new PriorityTask(1, "High priority task"));executor.execute(new PriorityTask(5, "Medium priority task"));executor.shutdown();}
}

1.5 优缺点

  • 优点

    • 直接在任务类中定义优先级逻辑,代码结构简单明了。
    • 无需额外的排序定义,PriorityBlockingQueue 自动根据 Comparable 实现排序。
  • 缺点

    • 任务类必须实现 Comparable 接口,优先级规则是硬编码在任务类中的,难以灵活修改。
    • 如果需要多种优先级规则,任务类代码会变得复杂,不适合多变的业务需求。

方法二:使用 Comparator 自定义排序规则

2.1 方案概述

在这种方法中,我们不再让任务类实现 Comparable 接口,而是使用 PriorityBlockingQueue 的构造方法传入一个 Comparator 对象。这样可以通过 Comparator 动态地定义任务的优先级排序规则。这种方式更加灵活,适合需要动态设置优先级或多重排序规则的场景。

2.2 实现步骤

  1. 定义任务类:实现 RunnableCallable 接口,无需实现 Comparable
  2. 创建优先级线程池:使用 PriorityBlockingQueue 作为任务队列,并传入自定义的 Comparator
  3. 提交任务到线程池:按照不同优先级提交任务,线程池会根据 Comparator 的排序规则来执行任务。

2.3 示例代码

import java.util.concurrent.*;public class Task implements Runnable {private final int priority;private final String name;public Task(int priority, String name) {this.priority = priority;this.name = name;}@Overridepublic void run() {System.out.println("Executing task: " + name + " with priority: " + priority);}public int getPriority() {return priority;}
}public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit,new PriorityBlockingQueue<>(11, Comparator.comparingInt(Task::getPriority)));}
}

2.4 使用示例

public class Main {public static void main(String[] args) {PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(2, 4, 1, TimeUnit.MINUTES);executor.execute(new Task(10, "Low priority task"));executor.execute(new Task(1, "High priority task"));executor.execute(new Task(5, "Medium priority task"));executor.shutdown();}
}

2.5 优缺点

  • 优点

    • 可以灵活定义优先级规则,通过传入不同的 Comparator 实现动态排序。
    • 更加清晰的结构,不需要在任务类中嵌入优先级排序逻辑,任务类更加独立。
  • 缺点

    • 相对复杂一些,需要定义额外的 Comparator
    • 可能需要管理多个 Comparator 实现,如果优先级规则过多,可能会增加一定的代码复杂度。

两种方法对比总结

比较项方法一:实现 Comparable方法二:使用 Comparator 自定义排序规则
代码结构任务类中包含优先级逻辑任务类和优先级规则分离
灵活性不灵活,排序规则固定灵活,可随时更改 Comparator
适用场景固定优先级规则动态优先级需求,多种排序规则
实现难度简单,适合初学者略复杂,需要理解 Comparator 使用
扩展性差,需改动任务类本身高,可复用不同 Comparator

总结

  • 如果您的任务优先级是固定的,而且排序规则简单,方法一:实现 Comparable 接口 更加直接明了。
  • 如果您需要灵活的优先级规则,或者希望在不同条件下使用不同的优先级排序规则,那么方法二:使用 Comparator 自定义排序规则更适合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/885228.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CES2025展会媒体发布现场邀约采访计划来啦!海外科技电子媒体报纸新闻宣传方案

【本篇由 言同数字全球媒体投放 原创】一、CES 2025 展会概述 CES&#xff08;国际消费电子展&#xff09; 是全球规模最大、最具影响力的消费电子展会之一&#xff0c;由美国消费技术协会&#xff08;CTA&#xff09;主办。每年1月&#xff0c;CES吸引来自全球各地的行业领袖…

Axure设计之三级联动选择器教程(中继器)

使用Axure设计三级联动选择器&#xff08;如省市区选择器&#xff09;时&#xff0c;可以利用中继器的数据存储和动态交互功能来实现。下面介绍中继器三级联动选择器设计的教程&#xff1a; 一、效果展示&#xff1a; 1、在三级联动选择器中&#xff0c;首先选择省份&#xff…

【1】 Kafka快速入门-从原理到实践

文章目录 🔍 一、引言📜 二、Kafka 的历史🏗️ 三、Kafka 的核心结构🖥️ (一)Broker📋 (二)Topic📄 (三)Partition📤 (四)Producer📥 (五)Consumer🐒 (六)Zookeeper💡 四、Kafka 的重点概念📨 (一)消息📏 (二)偏移量(Offset)🔄 (…

使用Docker-Compose安装redis,rabbitmq,nacos,mysql,nginx,tomcat,portainer组件教程

因为开发经常会用到一些组件&#xff0c;又不想在本地启动&#xff0c;所以买了个服务器&#xff0c;然后将这些组件都安装到服务器上以便开发使用。下面就记录下使用docker-compose安装组件的教程以及一些需要注意的地方。 关于docker和docker-compose的安装在另一篇博客中有…

安装PyG

PyG安装 官方链接 Installation — pytorch_geometric documentation (pytorch-geometric.readthedocs.io) 安装步骤&#xff1a; 步骤一&#xff1a;安装Anaconda和CUDA 安装Anaconda-CSDN博客安装CUDA-CSDN博客 步骤二&#xff1a;查看支持的Python版本 步骤三&#xf…

如何在Linux中使用Cron定时执行SQL任务

文章目录 前言一、方案分析二、使用步骤1.准备脚本2.crontab脚本执行 踩坑 前言 演示数据需要每天更新监控数据&#xff0c;不想手动执行&#xff0c;想到以下解决方案 navicat 创建定时任务java服务定时执行linux crontab 定时执行sql脚本 一、方案分析 我选择了第三个方案…

夜天之书 #103 开源嘉年华纪实

上周在北京参与了开源社主办的 2024 中国开源年会。其实相比于有点明显班味的“年会”&#xff0c;我的参会体验更像是经历了一场中国开源的年度嘉年华。这也是在会场和其他参会朋友交流时共同的体验&#xff1a;在开源社的 COSCon 活动上&#xff0c;能够最大限度地一次性见到…

鸿蒙开启无线调试

DevEco Studio没找到通过WI-FI连接手机的可视化操作按钮&#xff0c;就去官网看了下hdc - TCP连接场景 操作也比较简单&#xff1a; 第1步&#xff1a;PC通过USB连接手机/平板&#xff1b; 第2步&#xff1a;在手机/平板的“开发者选项”中打开“无线调试”并记录下IP和端口…

Android Handler

Handler用于多线程消息分发和处理。与handler相关的几个对象&#xff1a;Message, Looper&#xff0c;MessageQueue, ThreadLocal. Handler是Message的消费者。 MessageQueue是容器。 Looper是整个Message分发的驱动。 Handler中有多种发送消息的方法&#xff0c;其中postxx…

C语言操作符详解(下)

⽬录 1. 单⽬操作符 2. 逗号表达式 3. 下标访问[]、函数调⽤() 4. 结构成员访问操作符 5. 操作符的属性&#xff1a;优先级、结合性 6. 表达式求值 一 单⽬操作符 1 分类 &#xff01;、 、 -- 、 & 、 * 、 、 - 、 ~ 、 sizeof 、 ( 类型 ) 1.1 "&q…

【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!

数据集介绍 【数据集】道路事故识别数据集 8939 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含2种分类&#xff1a;{0: accident, 1: non-accident}。数据集来自国内外图片网站和视频截图。检测范围道路事故检测、监控视角检测、无人机视角检测、等&…

跑批为什么这么难

业务系统产生的明细数据通常要经过加工处理&#xff0c;按照一定逻辑计算成需要的结果&#xff0c;用以支持企业的经营活动。这类数据加工任务一般会有很多个&#xff0c;需要批量完成计算&#xff0c;在银行和保险行业常常被称为跑批&#xff0c;其它像石油、电力等行业也经常…

C++类型推导decltype和auto

auto用于变量声明时根据表达式自动推导其类型 int x 10; auto y x; // y 的类型是 int double a 5.5; auto b a * 2; // b 的类型是double decltype 是 C11 引入的一个关键字&#xff0c;用于查询表达式的类型。它允许编译器在编译时推断出一个表达式的类型&#xff0c;…

Flutter 鸿蒙next 中使用 MobX 进行状态管理

Flutter & 鸿蒙next 中使用 MobX 进行状态管理 在应用开发中&#xff0c;状态管理是一个至关重要的环节&#xff0c;特别是在复杂的Flutter或鸿蒙next项目中。状态的变化往往会影响UI的更新&#xff0c;因此&#xff0c;选择一种高效、灵活的状态管理工具显得尤为重要。Mo…

A012-基于Spring Boot的私房菜定制上门服务系统的设计与实现

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统私房菜定制上门服务系统信息管理难度大&#xff0c;容错率…

配有生物振膜的FPS电竞耳机,血手幽灵M760,精准定位每一声脚步

在PC上玩游戏的时候&#xff0c;一款高性能的游戏耳机是提升游戏体验的关键&#xff0c;特别是在吃鸡等FPS类游戏中&#xff0c;耳机不仅是听觉享受的工具&#xff0c;更是决定胜负的关键装备。如果耳机的环绕立体声效果能够及时准确的做出反应&#xff0c;我在游戏中就能清晰地…

状态模式(State Pattern)详解

1. 引言 在很多软件系统中&#xff0c;对象的行为往往依赖于其内部状态&#xff0c;而状态的变化又会影响对象的行为。状态模式&#xff08;State Pattern&#xff09;为解决这一问题提供了一种优雅的方法。通过将状态的行为封装到独立的状态对象中&#xff0c;可以使得对象在…

OceanBase详解及如何通过MySQL的lib库进行连接

OceanBase详解及如何通过MySQL的lib库进行连接 一、引言二、OceanBase概述1. 起源与发展2. 核心技术特点3. 应用场景三、OceanBase架构解析1. 系统架构2. 存储引擎3. 分布式架构四、如何使用MySQL的lib库连接OceanBase1. 前提条件2. 安装MySQL Connector/C3. 编写连接代码4. 编…

GPT原理;ChatGPT 等类似的问答系统工作流程如下;当用户向 ChatGPT 输入一个问题后:举例说明;ChatGPT不是通过索引搜索的传统知识库

目录 GPT原理 GPT架构 GPT 主要基于 Transformer 的解码器部分 ChatGPT 等类似的问答系统工作流程如下: 用户输入 文本预处理 模型处理 答案生成 输出回答 当用户向 ChatGPT 输入一个问题后:举例说明 文本预处理: ChatGPT不是通过索引搜索的传统知识库 GPT GPT…

【系统设计——认证授权——基本概念知识】

1. 认证和授权的区别 Authentication&#xff08;认证&#xff09; 是验证您的身份的凭据&#xff08;例如用户名/用户 ID 和密码&#xff09;&#xff0c;通过这个凭据&#xff0c;系统得以知道你就是你&#xff0c;也就是说系统存在你这个用户。所以&#xff0c;Authenticat…