小米面试:如何实现优先级线程池?

news/2024/11/15 23:48:01/文章来源:https://www.cnblogs.com/vipstone/p/18202253

我们知道,线程池中的所有线程都是由统一的线程工厂来创建的,当我们指定线程工厂时,线程池中的所有线程会使用我们指定的线程工厂来创建线程;但如果没有指定线程工厂,则会使用默认的线程工厂 DefaultThreadFactory 来创建线程,核心源码如下:

DefaultThreadFactory() {@SuppressWarnings("removal")SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix = "pool-" +poolNumber.getAndIncrement() +"-thread-";
}

那么问题来了,面试官问的是“如何实现优先级线程池?”,为什么我们一上来先讲了线程工厂呢?

这是因为,当我们讲到线程池优先级的时候,我们首先会想到线程的优先级,所以按照惯性思考,当面试官问到如何使用实现优先级线程池时,我们首先会考虑是不是在创建线程池的时候,可以通过某种方法来创建不同的线程优先级,从而实现优先级线程池?这就是开头我们一上来就讲线程工厂的原因。

那在线程工厂中如何设置线程的优先级呢?

它的设置也比较简单,如下代码所示:

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class CustomThreadPoolExecutorDemo {public static void main(String[] args) {// 自定义线程工厂ThreadFactory threadFactory = new CustomThreadFactory();// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), threadFactory);// 提交任务executor.execute(() -> System.out.println("Task 1"));executor.execute(() -> System.out.println("Task 2"));// 关闭线程池executor.shutdown();}static class CustomThreadFactory implements ThreadFactory {@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);// 设置线程优先级为最低优先级thread.setPriority(Thread.MIN_PRIORITY); return thread;}}
}

但是这种方式也有问题,那就是线程工厂是统一的,所以即使能在线程工厂中设置线程的优先级,那么也是将整个线程池中的所有线程都设置成统一的优先级了,而不能解决咱们本文提出的问题的,那如何才能实现优先级线程池呢?

1.优先级线程池实现思路

转念一想,既然不能在线程优先级上下功夫,但我们是否可以在线程池的任务队列上动点心思呢?

此时我们想到,可以使用 PriorityBlockingQueue 优先级队列来对任务进行排序啊(PriorityBlockingQueue 天生支持按照优先级自动排序任务的),这样不就能保证优先级高的任务会被线程池优先获取并执行了嘛

所以,有时候一条路走不通的时候,我们可以尝试换一个思路再试试。

2.优先级队列使用

我们先来测试一下 PriorityBlockingQueue 的使用,以尝试其可行性,示例代码如下:

import java.util.concurrent.PriorityBlockingQueue;public class PriorityBlockingQueueExample {public static void main(String[] args) {PriorityBlockingQueue<Task> priorityQueue = new PriorityBlockingQueue<>();// 添加任务到优先级队列priorityQueue.add(new Task("Task 1", 1));priorityQueue.add(new Task("Task 4", 4));priorityQueue.add(new Task("Task 3", 3));priorityQueue.add(new Task("Task 2", 2));// 从优先级队列中取出任务并执行while (!priorityQueue.isEmpty()) {Task task = priorityQueue.poll();if (task != null) {task.execute();}}}static class Task implements Comparable<Task> {private String name;private int priority;public Task(String name, int priority) {this.name = name;this.priority = priority;}public void execute() {System.out.println("Executing task: " + name);}@Overridepublic int compareTo(Task o) {return Integer.compare(this.priority, o.priority);}}
}

以上程序的执行结果如下:
image.png
从上述结果和代码可以看出,我们添加任务的顺序是:1、4、3、2,但最终会按照优先级排队执行的顺序是:1、2、3、4,执行结果符合我们的预期,优先级高的任务先被执行了(数字越小,优先级越高)。

3.优先级线程池

因此,我们实现的优先级线程池的最终代码如下:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class PriorityThreadPool {public static void main(String[] args) {BlockingQueue<Runnable> queue = new PriorityBlockingQueue<>(1000);ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,0, TimeUnit.SECONDS, queue);for (int i = 0; i < 100; i++) {int finalI = i;executor.execute(new PriorityTask(i, () -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("优先级:" + finalI);}));}}static class PriorityTask implements Runnable, Comparable<PriorityTask> {private final int priority;private final Runnable task;public PriorityTask(int priority, Runnable task) {this.priority = priority;this.task = task;}@Overridepublic void run() {task.run();}@Overridepublic int compareTo(PriorityTask other) {// 优先级高的任务应该排在前面(数字越小优先级越大)return Integer.compare(this.priority, other.priority);}}
}

以上程序执行结果如下:
image.png
从上述结果可以看出,线程池是完全按照优先级从高到低的顺序执行的(数字越小优先级越高),如果将 compareTo 中的排序方法倒置之后,那么线程池的执行顺序就完全相反了,可见使用 PriorityBlockingQueue 实现优先级线程池的效果非常显著。

课后思考

那么问题来了,PriorityBlockingQueue 在并发环境下会有线程安全问题吗?PriorityBlockingQueue 底层是如何保证线程安全的?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

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

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

相关文章

R机械设计 V4.1(2024.05.20)

R机械设计软件是兴力剑公司为工程师提供计算、查询服务的机械设计平台。 PC端包含一般设计资料、气、液压传动、联接件、机械传动、机器人、轴承、操作件、管件、润滑与密封、弹簧、材料、工具、模具、刀具、夹具、电机减速机、电气控制等多个大模块。用户只需输入已知条…

SS820-ASEMI高耐压肖特基二极管SS820

SS820-ASEMI高耐压肖特基二极管SS820编辑:ll SS820-ASEMI高耐压肖特基二极管SS820 型号:SS820 品牌:ASEMI 封装:SMB 最大平均正向电流(IF):8A 最大循环峰值反向电压(VRRM):200V 最大正向电压(VF):0.85V 工作温度:-55C~150C 反向恢复时间:5ns 芯片个数:1 芯片尺…

论文阅读:Reasoning with Latent Structure Refinement for Document-Level Relation Extraction

Nan G, Guo Z, Sekulić I, et al. Reasoning with latent structure refinement for document-level relation extraction[J]. arXiv preprint arXiv:2005.06312, 2020. 代码和预训练模型的github链接 LSR模型本文提出了用于文档级关系提取任务的Latent Structure Refinement(…

Oracel数据库常用命令集

一、数据库常用查询 1.查询数据库用户名 SELECT * FROM ALL_USERS; --或 select username from sys.dba_users;2、查询数据库名 select name from v$database;--- 如果是管理员等同权限,也可通过SQL*Plus或SQLcl中使用以下语句 show parameter db;3、查询数据库的实例名 selec…

使用私有云搭建ceph集群(一)

环境背景 本次ceph集群的搭建过程,利用学校数据中心服务器上部署的openstack私有云来进行实验学习 [登录账户]一、初始配置(两张网卡) network1配置 点击+ 创建网络进行网络的创建,首先对网络进行命名对网络中的子网进行配置,设置子网名称subnet1以及网络地址192.168.1.0/24…

OceanBase企业版4.x支持指定租户合并

下午同事询问3.x版本是否支持指定租户的合并操作,印象中没有,在官网上查询了下,也没有相关的操作手册,官方手册3.x地址如下: https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-0000000001417800 正好手头上还有4.x的环境,在查询4.x官网后发现,4.x版本已…

电视剧《庆余年2》第二季全集完整版高清迅雷下载1080p/720p[HD]

电视剧《庆余年2》作为继第一部的续集,持续了第一部的高燃剧情和精彩演绎,再次引起了广大观众的关注与热议。本剧以庆帝刘弼铭为主线,讲述了他在林殊之死后继续战斗的故事。此次续集的推出,再度掀起了一股庆余年的热潮,并展现了中国电视剧在制作和创作方面的高水平和创新力…

axis2生成wsdl回执参数首字母大小写问题

在跟局方对接接口的时候,局方回执我的wsdl接口,发现收不到同步回执,怀疑问题为回执参数首字母小写导致代码中的参数对象首字母确实是大写,但生成的wsdl文件确变成了小写,目前是用axis2生成的 参考 : https://bbs.csdn.net/topics/390457284 发现了变为小写的原因,选择使用…

怎样才能不让公司文件被泄露出去?

在信息化快速发展的今天,数据安全成为企业面临的一大挑战。公司文件一旦泄露,不仅会给企业带来巨大的经济损失,还可能严重影响企业的信誉。那么,怎样才能有效防止公司文件被泄露出去呢?以下是一些有效的策略。1. 加强员工培训和意识提升 很多时候,数据泄露是由员工的不当…

“0元体验”GPU算力,好易智算平台今日上线!

在数字化的浪潮中,算力作为新时代的生产力,正成为推动社会前进的关键力量。目前国内算力领域正面临需求碎片化、配套芯片技术不强、人才稀缺、传输能力弱等各个问题,关键核心在于算力对技术要求过高,造成供不应求、一卡难求等窘境。因此,好易智算平台创始人表示,正是因为…

轻量级新浪图床程序 幻想领域1.0发布

哇塞,终于有一款属于自己的图床了.幻想领域是使用 PHP 语言开发的一款轻量级的新浪图床系统.Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 轻量级新浪图床程序 幻想领域1.0发布 日期…

主流原型工具的设计

Axure(Axure RP) 1、交互设计:Axure提供了丰富的交互元素和动作,可以创建复杂的交互流程和状态转换,用于验证和演示产品功能。也就是在用户做什么行为的时候,触发了后面所设置的一系列动作。 2、高保真原型设计:Axure支持添加交互动画、过渡效果、表单输入和数据模拟等功…