03 Java线程池

本文深入探讨了线程池的必要性,包括资源管理和线程开销的重要性,详细介绍了线程池的创建方法和执行流程,以及如何合理配置线程池参数以提升系统性能。

为什么要有线程池

1 资源有限

没有用线程池的情况下,需要对每个任务创建一个线程,如果任务较多或线程执行较慢,线程会迅速增加,耗尽内存资源,进而导致服务崩溃。为了更合理的利用资源,需要对线程进行管理,为了避免任务过多而引起的服务异常,需要对任务进行管理

2 线程开销

线程每次创建和销毁时,都会有时间成本,为了提高性能,需要对已创建的线程进行复用。
使用线程池的目的总结来说,就是充分利用系统资源,同时避免过度调度引起的开销。

线程池该怎么用

1 线程池创建

1.1 Executors方式
  1. Executors.newFixedThreadPool:核心线程数一旦指定则固定,核心线程数和最大线程数相等,任务队列队列使用的是未指定容量的链表阻塞队列,链表阻塞队列未指定容量时,默认为Integer最大值。
  2. Executors.newCachedThreadPool:使用SynchronousQueue作为任务队列,新增和删除任务的操作为offer/poll的方式,最大线程数为Integer最大值,对于任意一个任务,每次都会创建一个新的线程来执行它。
  3. Executors.newSingleThreadExecutor:核心线程数和最大线程数都是1,任务队列队列使用的是未指定容量的链表阻塞队列,链表阻塞队列未指定容量时,默认为Integer最大值。
  4. Executors.newSingleThreadExecutor:创建一个定时任务线程池,核心线程数由输入参数指定,最大线程数为Integer.max,任务队列为延时阻塞队列,适用于在未来的某个时间点做某个任务。
  5. Executors.newWorkStealingPool:jdk8引入,内部会构建ForkJoinPool,利用working-stealing算法,并行的处理任务,但是不保证处理顺序。Fork/Join框架,把大任务分解成多个小任务,每个小任务执行完成之后,再合并成最终结果。work-stealing算法:某个线程从其他线程队列里窃取任务来执行。
1.2 ThreadPoolExecutor方式(推荐)

ExecutorService executorService = new ThreadPoolExecutor (corePoolSize,maxPoolSize,keepAliveTime,unit,任务队列,ThreadFactory,RejectedExecutionHandler);
建议使用ExecutorService作为静态类型,可以处理不带返回值的任务(execute)和带返回值的任务(submit),ThreadPoolExecutor接口默认无返回值,

  1. corePoolSize:核心线程数,当前线程数小于核心线程数时,创建新线程(充分利用资源),将当前任务作为线程的第一个任务来执行
  2. 任务队列:当前线程数大于核心线程数,将任务插入到队列,排队等待,线程会不断消费任务队列里的任务,
  3. maxPoolSize:最大线程数,当任务队列满了,且线程数小于最大线程数且小于最大容量(2^29-1),创建新线程
  4. keepAliveTime:如果线程数大于核心线程数,且空闲时长超过keepAliveTime,则销毁线程
  5. ThreadFactory:线程创建工厂,线程池会根据工厂方法来创建线程,通过工厂方法,自定义线程的名称、优先级及其他特性
  6. RejectedExecutionHandler:拒绝策略,当线程池饱和而无法继续执行任务时,采用拒绝策略来处理新任务。
    1. AbortPolicy:拒绝任务并抛出异常
    2. DiscardPolicy:拒绝任务但不抛出异常
    3. DiscardOldestPolicy:丢弃队列中最老的任务,并执行当前任务
    4. CallerRunsPolicy:主线程执行任务

2 执行任务

1 执行流程在这里插入图片描述

2 任务执行

  1. 获取任务:若是核心线程,使用take()方法从队列获取任务,执行完任务后,继续自旋从任务队列获取任务;若是非核心线程,使用poll(keepAliveTime)来获取任务,当执行完第一个任务后,会keepAliveTime超时,返回空任务;
  2. 执行任务:由woker线程调用任务的run方法

3 线程池关闭

  1. shutDown:将线程池状态设为关闭(ShutDown),停止接收新的任务,终止空闲的线程,正在运行的或者等待中的任务将会继续执行
  2. shutDownNow:将线程池状态设为停止,停止接收新的任务,终止(interrupt)所有线程,等待中的任务将不会继续执行,会返回未执行完的任务列表

线程池怎么实现的

1 线程池状态图

在这里插入图片描述

  1. Running:线程池正常运转,接收新的任务
  2. ShutDown:不接收新任务,队列中的任务和正在运行的任务会继续运行
  3. ShutDownNow:不接收新任务,队列中的任务不会运行,中止正在运行中的任务
  4. Tiding:线程池数量为空,队列任务为空时
  5. Terminated:terminated()方法执行完成之后

2 任务管理

使用阻塞队列来管理任务

3 线程管理

线程池数据结构

Java使用HashSet来管理线程(Worker类),那么HashSet如何唯一确定一个Worker呢?
Worker类并没有重写hashcode和equals,使用的是Object中默认的hashcode和equals方法,默认的equals方法是通过==运算符来判断,hashcode则为native方法,跟对象的monitor相关,有兴趣的可以去查看openjdk源码,hashcode方法可以保证对于同一个对象,hashcode方法会返回同一个值。

线程新增/删除

线程池为共享资源,对于它的操作需要保证线程安全,Java使用ReentrantLock锁来保证,任何对线程池的操作,首先要获取到锁。

基于51单片机,实现对直流电机的调速、测速以及正反转控制。项目包含完整的仿真文件、源程序、原理图和PCB设计文件,适合学习和实践51单片机在电机控制方面的应用。 功能特点 调速控制:通过按键调整PWM占空比,实现电机的速度调节。 测速功能:采用霍尔传感器非接触式测速,实时显示电机转速。 正反转控制:通过按键切换电机的正转和反转状态。 LCD显示:使用LCD1602液晶显示屏,显示当前的转速和PWM占空比。 硬件组成 主控制器:STC89C51/52单片机(与AT89S51/52、AT89C51/52通用)。 测速传感器:霍尔传感器,用于非接触式测速。 显示模块:LCD1602液晶显示屏,显示转速和占空比。 电机驱动:采用双H桥电路,控制电机的正反转和调速。 软件设计 编程语言:C语言。 开发环境:Keil uVision。 仿真工具:Proteus。 使用说明 液晶屏显示: 第一行显示电机转速(单位:转/分)。 第二行显示PWM占空比(0~100%)。 按键功能: 1键:加速键,短按占空比加1,长按连续加。 2键:减速键,短按占空比减1,长按连续减。 3键:反转切换键,按下后电机反转。 4键:正转切换键,按下后电机正转。 5键:开始暂停键,按一下开始,再按一下暂停。 注意事项 磁铁和霍尔元件的距离应保持在2mm左右,过近可能会在电机转动时碰到霍尔元件,过远则可能导致霍尔元件无法检测到磁铁。 资源文件 仿真文件:Proteus仿真文件,用于模拟电机控制系统的运行。 源程序:Keil uVision项目文件,包含完整的C语言源代码。 原理图:电路设计原理图,详细展示了各模块的连接方式。 PCB设计:PCB布局文件,可用于实际电路板的制作。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值