网站首页 > java教程 正文
更多内容,欢迎关注微信公众号:全菜工程师小辉~
之所以要使用线程池,是因为使用new Thread在大型项目中是有弊端的:
- 每次new Thread新建对象,性能差
- 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能会造成过多占用系统资源而导致OOM
- 缺少更多功能,如定期执行等
而线程池的好处:
- 重用存在的线程,减少对象创建、消亡的开销,性能佳
- 可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞
- 提供定时执行、定期执行、单线程、并发数控制等功能
状态池的状态转换
线程池的类继承关系
- Executor是一个顶层接口,在它里面只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型,从字面意思可以理解,就是用来执行传进去的任务的
- ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等
- 抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService中声明的所有方法
- ThreadPoolExecutor继承了类AbstractExecutorService。
ThreadPoolExecutor的方法说明
- execute()实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行
- submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果
- shutdown()优雅关闭线程池
- shutdownNow()强制关闭线程池
还有很多其他的方法:比如:getQueue() 、getPoolSize() 、getActiveCount()、getCompletedTaskCount()等获取与线程池相关属性的方法,可以用于线程池监控,有兴趣的朋友可以自行查阅API。
更多ThreadPoolExecutor配置的详细说明,点击查看:还在用Executors创建线程池?小心内存溢出
ScheduledExecutorService使用说明
@Slf4j public class ThreadPoolExample { public static void main(String[] args) { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); // 延时任务 // executorService.schedule(()-> // log.warn("schedule run"), 3, TimeUnit.SECONDS); // 固定速率任务 executorService.scheduleAtFixedRate(() -> log.warn("schedule run"), 1, 3, TimeUnit.SECONDS); // executorService.shutdown(); // Timer也能执行定时任务,不过还是推荐用ScheduledExecutorService // Timer timer = new Timer(); // timer.schedule(new TimerTask() { // @Override // public void run() { // log.warn("timer run"); // } // }, new Date(), 5 * 1000); } }
特别提示:通过ScheduledExecutorService执行的周期任务,如果任务执行过程中抛出了异常,那么ScheduledExecutorService就会停止执行任务,而且也不会再周期地执行该任务了。所以如果想保持任务周期执行,需要catch一切可能的异常。
线程池核心线程数配置推荐
CPU密集型任务:尽量压榨CPU,参考值设置为NCPU+1
IO密集型任务:参考值可以设置为2*NCPU
相关的线程池
Spring的异步线程池
TaskExecutor是Spring异步线程池的接口,继承Java.util.concurrent.Executor接口
Spring已经实现的异步线程池(TaskExecutor的实现类):
- SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
- SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方
- ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类
- SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类
- ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装
Spring的异步线程池的使用
- @Async将方法标注为异步方法,Spring扫描到后,执行该方法时,会另起新线程去执行,非常简单
- 为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync
@Async所修饰的函数不要定义为static类型,这样异步调用不会生效
猜你喜欢
- 2024-09-16 java-线程池详解(java线程池入门)
- 2024-09-16 线程进阶:实战应用之Java线程池全面解析
- 2024-09-16 Java开发之高并发必备篇(七)——线程池
- 2024-09-16 Java-线程池专题(什么是线程池,如何使用,为什么要用)
- 2024-09-16 Java线程之Executors线程池的原理和使用
- 2024-09-16 Java的四种线程池的使用,以及自定义线程工厂
- 2024-09-16 探索JAVA并发 - 线程池详解(java多线程并发编程 线程池)
- 2024-09-16 Java线程池的概念及使用(java 线程池原理详解)
- 2024-09-16 Java线程池核心(十一):线程池状态
- 2024-09-16 Java 线程池(java线程池原理)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)