深度思考线程池面经之四:使用线程池的各种特性

8 线程池(百度acg百度云一面)

8.1 你是用到哪个线程池呢,在哪个场景中使用呢

答:在秒杀系统中使用了newCachedThreadPool这个线程池

8.2 自定义线程池的参数,你是怎么设置的呢

8.3 写一个自定义线程池,要求核心线程数8,最大线程数10,有界队列10,现让你执行100个打印任务,同时还需要你自定义线程工厂,要求实现线程的优先级,所属线程组,线程异常处理策略,自定义线程名

package demo;import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;// 自定义线程工厂
class DIYThreadFactory implements ThreadFactory {public DIYThreadFactory(ThreadGroup threadGroup, String poolName, Integer priority, boolean isDaemon, Thread.UncaughtExceptionHandler handler) {this.threadGroup = threadGroup;this.threadPrefix = "pool-"+poolName+"-thread";this.priority = priority;this.isDaemon = isDaemon;this.handler = handler;}//线程名private final AtomicInteger atomicInteger = new AtomicInteger(0);// 线程分组private final ThreadGroup threadGroup;//线程前缀名private final String threadPrefix;private final Integer priority;// 是否后台线程private final boolean isDaemon;// 异常处理器private final Thread.UncaughtExceptionHandler handler;@Overridepublic Thread newThread(Runnable r) {Thread t=new Thread(threadGroup,r,threadPrefix+atomicInteger.getAndIncrement(),0);if(t.isDaemon()!=isDaemon){t.setDaemon(isDaemon);}t.setPriority(priority);if(handler!=null){t.setUncaughtExceptionHandler(handler);}return t;}
}
// 自定义拒绝策略
class DIYRejectStrategy implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {System.out.println("Task " + r.toString() + " rejected from " + executor.toString());// 这里你可以选择做其他的操作,例如记录日志、抛出异常、尝试重新添加任务等}
}
public class Test{private static final BlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingDeque<>(1000);public static void main(String[] args) {BlockingDeque<Runnable>bq=new LinkedBlockingDeque<>(10);Thread.UncaughtExceptionHandler handler=new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("Thread " + t.getName() + " encountered exception: " + e.getMessage());}};DIYThreadFactory diyThreadFactory=new DIYThreadFactory(null,"yxg",1,false,handler);ThreadPoolExecutor tpe=new ThreadPoolExecutor(2,10,10,TimeUnit.SECONDS,bq,diyThreadFactory,new DIYRejectStrategy());for (int i = 0; i < 100; i++) {final int fi = i;tpe.execute(new Runnable() {@Overridepublic void run() {if (fi%5==0){int i1 = fi / 0;}System.out.println("send "+ fi +" th msg");}});}tpe.shutdown();}
}

8.3.1 下面这道报错代码怎么解决

for (int i = 0; i < 100; i++) {tpe.execute(new Runnable() {@Overridepublic void run() {System.out.println("send "+ finalI +" th msg");}});
}

你在匿名内部类中尝试访问循环变量i。在Java 8之前,当你在匿名内部类中使用一个外部变量,那个变量必须是final的。从Java 8开始,你可以在lambda表达式或匿名内部类中使用所谓的“effectively final”的变量,即它不必明确地声明为final,但你也不能在其后更改它。

你的代码中,变量i在循环中是会改变的,所以不能直接在匿名内部类中使用。你之前的注释的代码(int finalI = i;)是正确的,因为你在创建了一个effectively final的局部变量finalI,并将i的值赋给它。

解决方案:

  1. 使用一个effectively final的局部变量来传递i的值给匿名内部类。
for (int i = 0; i < 100; i++) {int finalI = i;tpe.execute(new Runnable() {@Overridepublic void run() {System.out.println("send "+ finalI +" th msg");}});
}
  1. 或者,你可以使用Java 8的lambda表达式,这样会更简洁:
for (int i = 0; i < 100; i++) {int finalI = i;tpe.execute(() -> System.out.println("send "+ finalI +" th msg"));
}

在这两种解决方案中,我们都使用了局部变量finalI来在匿名内部类或lambda表达式中使用循环变量i

8.3.2 什么是effective final

"effectively final"是Java 8引入的一个概念,它允许你在匿名内部类或lambda表达式中引用没有被明确标记为final的局部变量,但有一个限制:这个局部变量在赋值后不能再次被修改。

简单地说,一个局部变量如果满足以下条件,它就是"effectively final"的:

  1. 它在初始化之后不再被赋新的值。
  2. 它不需要明确地使用final关键字来修饰。

例如:

int x = 10;
// some code...
x = 20;  // After this assignment, 'x' is no longer effectively final

如果你去掉x = 20;这行代码,即便x没有被明确地标记为final,它仍然是"effectively final"的,因为在初始化后它没有被赋新的值。

这个概念的引入是为了让Java的语法更加灵活,尤其是在使用lambda表达式时。在Java 8之前,如果你想在匿名内部类中引用一个局部变量,那么这个变量必须被明确地声明为final。而在Java 8及其后续版本中,只要局部变量满足"effectively final"的条件,即使它没有被明确地声明为final,你也可以在lambda表达式或匿名内部类中使用它。

8.4 使用线程池时,设置各项参数的依据有哪些(重要)

答:我的回答:qps(任务数),任务的执行时间,机器资源的限制

使用线程池时,设置参数要根据具体应用场景和需求来决定。以下是设置线程池参数时需要考虑的一些常见场景和因素:

  1. 任务的性质

    • 计算密集型任务:这些任务主要消耗CPU资源。线程池的大小应该接近于系统的可用处理器的数量,这样可以最大程度地利用CPU资源。

    • I/O密集型任务:这些任务可能需要等待外部资源,如文件系统、数据库或网络。由于线程经常被阻塞,可以配置一个线程数大于处理器数量的线程池,这样可以保持处理器始终在工作。

    • 混合型任务:当有计算和I/O混合的任务时,需要对线程池的大小进行细致的调整。

  2. 任务的持续时间和频率

    • 长时间运行的任务:这可能会使线程池中的所有线程都被占用,导致新任务等待。对于这种情况,可能需要一个更大的线程池。

    • 短暂、频繁的任务:可缓存的线程池可能更为适用。

  3. 任务的优先级

    • 一些任务可能比其他任务更为紧急。虽然Java线程池本身不支持优先级队列,但可以通过自定义队列和任务来模拟。
  4. 任务间的依赖关系

    • 如果任务B依赖于任务A的结果,这可能会引入死锁风险。这种情况下,需要特别注意线程池的大小和队列策略。
  5. 资源限制

    • 如果系统有限的资源(如数据库连接),过多的并发请求可能导致资源耗尽。这时,线程池的大小和队列的容量可能需要限制以防止资源竞争。
  6. 响应时间要求

    • 如果系统对响应时间有严格的要求,可能需要更多的线程来确保任务能够快速开始执行,而不是在队列中等待。
  7. 拒绝策略

    • 当队列和线程池都满时,应如何处理新提交的任务?是否应该抛出异常、丢弃任务、或使提交任务的线程自己来执行任务?
  8. 线程池的生命周期和管理

    • 如果应用经常启动和关闭,固定大小的线程池可能更适合,因为它们在空闲时不会关闭线程。但是,如果线程池的生命周期很长,并且任务有高峰和低谷,缓存线程池可能更为合适,因为它可以在低谷时回收线程。

考虑这些场景和因素,可以帮助设计一个高效、响应迅速并且资源利用率高的线程池。但仍建议进行性能测试和监控,以确保所选参数在实际生产环境中的表现符合预期。

8.5 基于各种场景,你会怎么使用线程池呢,参数怎么设置

8.6 线程优先级内部的原理是怎么实现的,高优先级的线程是先执行吗?难道任务队列内部会对他们进行排序吗

线程的优先级是与操作系统级的线程调度有关的,Java的线程优先级映射到操作系统的线程优先级。线程调度机制的实现是操作系统依赖的,所以Java线程优先级的行为也可能因操作系统而异。以下是一些一般的概念:

  • 优先级为提示:线程优先级在Java中主要作为线程调度的提示。高优先级的线程在大多数情况下会比低优先级的线程得到更多的执行机会,但这并不是一个严格的保证。
  • 不同的调度策略:大多数现代操作系统使用优先级的抢先式调度(preemptive scheduling)机制,即任何时候只要有一个更高优先级的线程就绪,当前正在执行的低优先级线程就会被打断。
  • 没有排序操作系统的线程调度器不会持续地重新排序就绪线程。而是在选择下一个要执行的线程时,根据优先级考虑它们。

8.7 操作系统的线程调度器不会持续地重新排序就绪线程。而是在选择下一个要执行的线程时,根据优先级考虑它们。 但是java是不是可以自定义一个优先级队列,实现任务的重排序的功能?(重要)

是的,Java确实提供了工具来自定义优先级队列,并通过它实现任务重排序功能。java.util.PriorityQueue 是Java标准库中的一个类,它实现了一个优先队列。这个队列内部是使用堆(heap)数据结构来实现的,这使得每次从队列中取出的元素都是具有最高优先级的。

如果你想在多线程环境中,比如线程池中,使用基于优先级的任务调度,可以结合 PriorityQueueThreadPoolExecutor 来实现。你可以提供一个自定义的 BlockingQueue(例如,基于 PriorityQueue 的实现)给 ThreadPoolExecutor,并确保任务对象实现了 Comparable 接口,或者在构建 PriorityQueue 时提供一个 Comparator

下面是一个简单示例,展示了如何使用 PriorityQueueThreadPoolExecutor 提供基于优先级的任务调度:

import java.util.concurrent.*;public class PriorityTask implements Runnable, Comparable<PriorityTask> {private int priority;private String name;public PriorityTask(int priority, String name) {this.priority = priority;this.name = name;}@Overridepublic void run() {System.out.println("Executing: " + name);}@Overridepublic int compareTo(PriorityTask o) {return Integer.compare(o.priority, this.priority); // higher values mean higher priority here}public static void main(String[] args) {BlockingQueue<PriorityTask> priorityQueue = new PriorityBlockingQueue<>();ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 1, TimeUnit.SECONDS, priorityQueue);executor.submit(new PriorityTask(1, "low-priority-task"));executor.submit(new PriorityTask(3, "medium-priority-task"));executor.submit(new PriorityTask(2, "high-priority-task"));executor.shutdown();}
}

在上述示例中,任务会按优先级从高到低执行。但是,你应该小心使用基于优先级的调度,因为它可能会导致低优先级的任务饥饿,即在极端情况下,低优先级的任务可能永远得不到执行的机会。

8.7.1 任务的优先级和线程的优先级是不同的,对吧

是的,任务的优先级和线程的优先级是两个不同的概念。让我们详细区分它们:

  1. 线程的优先级

    • 线程优先级是一个整数,通常在操作系统中,每个线程都有一个与之相关的优先级。

    • 在Java中,线程优先级可以使用Thread.setPriority(int)方法进行设置,范围从Thread.MIN_PRIORITY (即值1) 到 Thread.MAX_PRIORITY (即值10)。默认的优先级是Thread.NORM_PRIORITY (即值5)。

    • 线程的优先级是给线程调度器的一个提示,告诉调度器哪些线程更应该得到执行的机会。但是,具体的行为取决于操作系统的线程调度策略。

    • 在某些系统中,线程优先级可能并不会严格地被考虑;而在其他系统中,它可能会被严格地遵循。因此,依赖线程优先级可能会导致跨平台的不可预测行为。

  2. 任务的优先级

    • 任务的优先级通常用于在基于优先级的队列中对任务进行排序,如上文中所示的PriorityBlockingQueue

    • 任务的优先级通常与具体的应用逻辑有关,例如,在一个任务队列中,某些任务由于其紧迫性或重要性可能被赋予较高的优先级。

    • 当使用线程池和优先级任务队列时,线程池中的工作线程将按照任务的优先级来选择任务执行。但这与线程自身的优先级无关。

    • 使用任务优先级时要小心,以避免低优先级任务的饥饿。

总结起来,线程优先级与操作系统的线程调度相关,而任务优先级与如何从队列中选择要执行的任务相关。在设计系统时,应明确考虑这两种优先级的影响和它们的使用场景。

8.7.2 java线程池如何实现任务优先级

1 写法一
import java.util.concurrent.*;public class PriorityTask implements Runnable, Comparable<PriorityTask> {private int priority;private String name;public PriorityTask(int priority, String name) {this.priority = priority;this.name = name;}@Overridepublic void run() {System.out.println("Executing: " + name);}@Overridepublic int compareTo(PriorityTask o) {return Integer.compare(o.priority, this.priority); // higher values mean higher priority here}public static void main(String[] args) {PriorityBlockingQueue<PriorityTask> priorityQueue = new PriorityBlockingQueue<>();ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 1, TimeUnit.SECONDS, priorityQueue);executor.submit(new PriorityTask(1, "low-priority-task"));executor.submit(new PriorityTask(3, "medium-priority-task"));executor.submit(new PriorityTask(2, "high-priority-task"));executor.shutdown();}
}
2 写法二: 推荐
import java.util.concurrent.*;public class PriorityTask implements Runnable{private int priority;private String name;public PriorityTask(int priority, String name) {this.priority = priority;this.name = name;}@Overridepublic void run() {System.out.println("Executing: " + name);}public static void main(String[] args) {PriorityBlockingQueue<PriorityTask> priorityQueue = new PriorityBlockingQueue<>(10,(o1, o2)->(o2.priority-o1.priority));ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 1, TimeUnit.SECONDS, priorityQueue);executor.submit(new PriorityTask(1, "low-priority-task"));executor.submit(new PriorityTask(3, "medium-priority-task"));executor.submit(new PriorityTask(2, "high-priority-task"));executor.shutdown();}
}

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

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

相关文章

Python接口自动化-requests模块之post请求

一、源码解析 def post(url, dataNone, jsonNone, **kwargs):r"""Sends a POST request.:param url: URL for the new :class:Request object.:param data: (optional) Dictionary, list of tuples, bytes, or file-likeobject to send in the body of the :cl…

Vue.prototype详解

一&#xff1a;简介 在 Vue.js 中&#xff0c;经常会看到 this.$XXX 这种写法&#xff0c;那么这个是什么呢&#xff1f;其实这里就是使用 Vue.prototype 所定义的一个挂载到本身的全局方法&#xff0c;主要是为了防止全局变量的污染&#xff0c;所以我们来共同商议的一种写法…

软件项目管理实践指南:有效规划、执行和控制

软件项目管理是使软件产品、应用程序和系统成功交付的重要规程。它有助于确保软件在预算内按时开发&#xff0c;同时满足客户的质量和功能需求。 软件项目管理是管理软件项目生命周期的一种有组织的方法&#xff0c;包括计划、开发、发布、维护和支持。它是在满足客户需求的同时…

RocketMQ为什么要保证订阅关系一致

这篇文章&#xff0c;笔者想聊聊 RocketMQ 最佳实践之一&#xff1a;保证订阅关系一致。 订阅关系一致指的是同一个消费者 Group ID 下所有 Consumer 实例所订阅的 Topic 、Tag 必须完全一致。 如果订阅关系不一致&#xff0c;消息消费的逻辑就会混乱&#xff0c;甚至导致消息丢…

EMNLP 2023 录用论文公布,速看NLP各领域最新SOTA方案

EMNLP 2023 近日公布了录用论文。 开始前以防有同学不了解这个会议&#xff0c;先简单介绍介绍&#xff1a;EMNLP 是NLP 四大顶会之一&#xff0c;ACL大家应该都很熟吧&#xff0c;EMNLP就是由 ACL 下属的SIGDAT小组主办的NLP领域顶级国际会议&#xff0c;一年举办一次。相较于…

【Vue3 Antdv】Ant Design Vue文字溢出鼠标滑上显示tooltip。不溢出,鼠标滑上不显示tooltip

组件封装代码 <template><a-tooltip mouseenter"showToolTip" v-bind"getBindValue"><template #title>{{ props.title }}</template><slot><span>{{ props.title }}</span></slot></a-tooltip> &…

DB2 HADR 配置 centos 7配置 DB2 HADR 版本 11.1,【亲测可用】全网最细

DB2 HADR 配置 centos 7配置 DB2 HADR 版本 11.1&#xff0c;【亲测可用】全网最细的男人 操作系统 linux centos7 DB2版本 11.1 主库 192.168.46.70 备库 192.168.46.71 参考文章&#xff1a;一步一个脚印 DB2 10.5 HADR 主备库配置 前置条件 机器之间时间必须同步&#xff0…

C++11新特性(lambda,可变参数模板,包装器,bind)

lambda表达式是什么&#xff1f;包装器又是什么&#xff1f;有什么作用&#xff1f;莫急&#xff0c;此篇文章将详细带你探讨它们的作用。很多同学在学习时害怕这些东西&#xff0c;其实都是方便使用的工具&#xff0c;很多情况下我们学这些新的东西觉得麻烦&#xff0c;累赘&a…

uni-app开发微信小程序的报错[渲染层错误]排查及解决

一、报错信息 [渲染层错误] Framework nner error (expect FLOW INITIALCREATION end but get FLOW CREATE-NODE) 二、原因分析及解决方案 第一种 原因&#xff1a;基础库版本的原因导致的。 解决&#xff1a; 1.修改调试基础库版本 2.详情—>本地设置—>调试基础库…

扎根嵌入式行业需要什么学历文凭?

在嵌入式行业&#xff0c;学历并不是唯一关键。我本人拥有电子工程学士学位&#xff0c;但嵌入式行业更看重实际技能和经验。视频后方有免费的嵌入式学习资料&#xff0c;入门和进阶内容都涵盖其中。嵌入式行业一般接纳各种学历&#xff0c;从专科到本科到研究生&#xff0c;甚…

CentOS 安装MySQL 详细教程

参考:https://www.cnblogs.com/dotnetcrazy/p/10871352.html 参考:https://www.cnblogs.com/qiujz/p/13390811.html 参考:https://blog.csdn.net/darry1990/article/details/130419433 一、安装 一、进入安装目录 将账户切换到root账户下&#xff0c;进入local目录下 cd /usr…

通过商品ID获取淘宝天猫商品评论数据,淘宝商品评论接口,淘宝商品评论api接口

淘宝商品评论内容数据接口可以通过以下步骤获取&#xff1a; 登录淘宝开放平台&#xff0c;进入API管理控制台。在API管理控制台中创建一个应用&#xff0c;获取到应用的App Key和Secret Key。构造请求URL&#xff0c;请求URL由App Key和Secret Key拼接而成&#xff0c;请求UR…

【每日一题】ABC311G - One More Grid Task | 单调栈 | 简单

题目内容 原题链接 给定一个 n n n 行 m m m 列的矩阵&#xff0c;问权值最大的子矩阵的权值是多少。 对于一个矩阵&#xff0c;其权值定义为矩阵中的最小值 m i n v minv minv 乘上矩阵中所有元素的和。 数据范围 1 ≤ n , m ≤ 300 1\leq n,m \leq 300 1≤n,m≤300 1 ≤…

用Python和开源NLP工具库开发一个小型聊天机器人原型

为了创建一个小型聊天机器人原型&#xff0c;我们可以使用Python和开源NLP工具库spaCy。在本示例中&#xff0c;我们将演示如何创建一个简单的问答聊天机器人&#xff0c;它可以回答一些基本问题。 首先&#xff0c;确保您已经安装了Python和spaCy&#xff0c;然后下载spaCy的…

VUE3页面截取部署后的二级目录地址

用vue3开发了一个项目&#xff0c;只能部署在根目录&#xff0c;不能加二级目录&#xff0c;后来网上找了解决方案&#xff0c;在vite.config.ts中增加base: ./,配置解决问题&#xff0c;参考下图&#xff1a; 但部署后要获取部署的二级目录地址切遇到问题&#xff0c;后来想了…

数字化教育的未来:数字孪生技术助力校园创新

随着科技的飞速发展&#xff0c;智慧校园成为教育领域的新宠。数字孪生技术&#xff0c;作为一项新兴技术&#xff0c;正日益深刻地影响着校园的运营和管理。它为学校提供了前所未有的工具和资源&#xff0c;使校园管理更加高效、智能化。本文将探讨数字孪生技术如何助力智慧校…

深度学习中的激活函数

给定一个线性变换可以把x的值映射到一条直线上&#xff0c;如下图 输出结果就是y1w1xb1 如果y1经过一个线性变换得到一个y2&#xff0c;那么x和y2的关系是什么&#xff1f; 答案&#xff0c;毫无疑问是一条直线&#xff0c;不管如何的线性变换&#xff0c;依旧是一个线性的问…

【网路安全 --- Linux,window常用命令】网络安全领域,Linux和Windows常用命令,记住这些就够了,收藏起来学习吧!!

一&#xff0c;Linux 1-1 重要文件目录 1-1-1 系统运行级别 /etc/inittab 1-1-2 开机启动配置文件 /etc/rc.local /etc/rc.d/rc[0~6].d## 当我们需要开机启动自己的脚本时&#xff0c;只需要将可执行脚本丢在 /etc/init.d 目录下&#xff0c;然后在 /etc/rc.d/rc*.d 中建…

2022年最新Python大数据之Python基础【五】(字典)

文章目录 9、字典的定义10、字典的增加11、字典的删除12、字典的修改13、字典的查询14、字典的遍历 9、字典的定义 格式&#xff1a;变量 {key1 : value1, key2: value2…}空字典定义&#xff1a; {}dict&#xff08;&#xff09; 字典中键不能重复&#xff0c;是唯一的&…

Mysql的安装配置教程(详细)

MySQL是一种流行的关系型数据库管理系统&#xff0c;用于存储和管理数据。下面是MySQL的安装和配置教程的详细步骤&#xff1a; 下载MySQL安装程序&#xff1a; 访问MySQL官方网站&#xff08;https://dev.mysql.com/downloads/mysql/&#xff09;。选择适合你操作系统的版本&a…