深入浅出JAVA线程池使用原理2
一、Executor框架介绍
Executor框架将Java多线程程序分解成若干个任务,将这些任务分配给若干个线程来处理,并得到任务的结果
1.1、Executor框架组成
任务:被执行任务需要实现的接口:Runnable接口或Callable接口
任务的执行:任务执行的核心接口Executor以及其子类ExecutorService接口
任务的结果:包括Future接口以及Future接口的实现类FutureTask类
Executor接口是Executor框架的基础,将任务的提交与执行分离开
ThreadPoolExecutor:线程池核心实现类,用来执行提交的任务
ScheduledThreadPoolExecutor:在给定的延迟时间后执行或定期执行任务,相当于ThreadPoolExecutor的定时器版本
Future接口和实现类FutureTask代表异步处理的结果
Runnable接口和Callable接口都是当做任务被ThreadPoolExecutor和ScheduledThreadPoolExecutor来执行
二、ThreadPoolExecutor详解
ThreadPoolExecutor通常可以使用工厂类Executors来创建,可以有以下三种类型:
SingleThreadExecutor:单线程线程池执行器,适用于需要保证顺序地执行各个任务且不会出现多线程同时活动的情况
FixedThreadPool:创建使用固定线程数量的线程池,可以限制当前线程数量,比较常用。
CachedThreadPool:大小无界的线程池,适用于需要执行大量短期异步任务的场景或者是服务器负载较小的情况
2.1、FixedThreadPool详解
源码如下:
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
可以看出只需要设置两个参数:线程数量和线程工厂(可不传)
1.这里可以看出FixedThreadPool使用的工作队列是无界的链表结构的阻塞队列,所以这里的maximumPoolSize参数就设置成了和coolPoolSize一样的值,因为设置再大也失去了意义;
2.多余线程保持活跃的时间设置成了0,也就是多余的空闲线程会立即终止;
3.由于队列是无界的,所以线程池不会出现拒绝任务的情况,所以也不会用到饱和策略;
4.整体的工作流程就是:
线程池中线程数量少于corePoolSize时会先创建新线程来预热,达到之后就将任务放入LinkedBlockingQueue队列中,线程执行完任务之后会循环从队列中获取任务来执行
2.2、SingleThreadExecutor详解
源码如下:
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
可以看出SingleThreadExecutor和FixedThreadPool几乎一样,只是线程只会有一个线程,相比于FixedThreadPool的好处就是可以保证任务的顺序性
2.3、CachedThreadPool详解
源码如下:
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
可以看出也只需要设置线程工厂一个参数,而其他参数都是固定的,corePoolSize设置为0,即corePool为空;maximumPoolSize设置为了Integer的最大值就表示是无大小限制了。keepAliveTime设置成了60秒;队列使用了SynchronousQueue
整体的工作流程为:
1.提交任务到SynchronousQueue队列中,如果线程池中有空余的线程在执行poll操作,则此任务就会被该线程获取执行
2.如果线程池中没有空闲线程,则就会在线程池中创建新的线程来执行poll操作获取任务
3.线程池中的空闲线程如果poll操作没有获取到任务,则会等待60秒,如果没有等待任务则线程终止
所以CachedThreadPool的好处是没有任务的时候,线程池中不需要创建线程等待任务,或者任务执行完之后,线程会在不久就会释放,节省了资源。但是如果任务数量较大,且线程处理任务的速度慢于主线程提交任务的速度,那么线程池中就会不停的创建新线程来执行,
就会有线程数量过多而导致CPU和内存资源被消耗尽的情况
三、FutureTask详解
3.1、FutureTask用法
FutureTask除了实现了Future接口,还实现了Runnable接口,所以FutureTask可以被Executor执行,也可以直接调用本身的run方法执行。
FutureTask有三种状态:未启动(未执行run方法)、已启动(执行run方法中)、已结束(run方法结束或抛出异常)
当FutureTask不是处于已结束状态时,调用get方法会阻塞当前线程知道任务结束;当处于已结束状态时,调用get方法会返回任务执行的结果或抛出对应的异常
当FutureTask处于未启动状态时,调用cancel方法会导致该任务永远不会被执行;
当FutureTask处于已启动状态时,调用cancel(true)方法会中断执行的任务,调用cancel(false)方法将不会对正在执行此任务的线程产生影响
当FutureTask处于已结束状态时,调用cancel方法会返回false
3.2、FutureTask实现原理
FutureTask底层是基于AQS(抽象同步队列)实现的
是
深入浅出JAVA线程池使用原理2的更多相关文章
- 深入浅出JAVA线程池使用原理1
前言: Java中的线程池是并发框架中运用最多的,几乎所有需要异步或并发执行任务的程序都可以使用线程池,线程池主要有三个好处: 1.降低资源消耗:可以重复使用已经创建的线程降低线程创建和销毁带来的消耗 ...
- 深入浅出Java线程池:源码篇
前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...
- Java线程池的原理及几类线程池的介绍
刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
- Java 线程池的原理与实现 (转)
最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. [分享]Java 线程池的原理与实现 这几天主要是狂看源程序,在弥补了一些以前知 ...
- Java线程池实现原理及其在美团业务中的实践
本文转载自Java线程池实现原理及其在美团业务中的实践 导语 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供 ...
- 我眼中的java线程池实现原理
最近在看java线程池实现方面的源码,在此做个小结,因为网上关于线程池源码分析的博客挺多的,我也不打算重复造轮子啦,仅仅用纯语言描述的方式做做总结啦! 个人认为要想理解清楚java线程池实现原理,明白 ...
- Java 线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java 线程池(ThreadPoolExecutor)原理解析
在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...
随机推荐
- 自动化测试工具Katalon简单使用
前一段时间接触了下Katalon,当时只是简单用了下,今天看到Katalon给发邮件,发现都忘记了,因此重新学习并记录下来 Katalon是在Selemium相同的内核上构建起来的一个自动化测试工具 ...
- fiddler 使用记录
fiddler 工作原理 Fiddler 启动后将自己变成一个代理服务器,这个代理服务器默认监听 127.0.0.1:8888. Filddler 启动后浏览器的代理会被自动更改为 127.0.0.1 ...
- windows pm2 启动nodejs失败:Error: EBADF: bad file descriptor, uv_pipe_open
windows下打开命令窗口,安装pm2:npm install pm2 -g pm2成功安装,在项目目录下用pm2启动服务:pm2 start index.js,结果启动失败,错误如下: .pm2\ ...
- ActiveQt框架 禁止弹出ActiveX控件交互提示
重点重写QAxBindable的createAggregate() 参考Qt例子: qtactiveqt\activeqt\opengl\glbox.cpp
- array_walk 与 array_map的 区别
1.array_walk是用于用户自定义的函数,所以想用array_walk($aIds, "trim");去掉数据元素中的空格是达不到目的的只能用array_walk($aIds ...
- HTML自动跳转
本文首发于 http://youngzy.com/ 关于页面的自动跳转,以前知道有JavaScript的方法,直接设置window.location 或者在setTimeout 函数里进行设置. 现在 ...
- Nestjs 上传文件
Docs: https://docs.nestjs.com/techniques/file-upload 上传单文件 @Post('upload') @UseInterceptors(FileInte ...
- hibernate的面试总结
hibenate的面试总结. 可能现在大家常常还会遇到一个些面试的时候问一些关于hibernate的问题,我个人觉得,这些东西一般做过开发的人在使用上没有任何的问题的,但是如果是要你来说就不一定能够说 ...
- Oracle课程档案,第四天
“子查询”就是查询中嵌套着另一个查询,也即通过SELECT语句的嵌套使用形成子查询.当我们不知道特定的查询条件时,可以用子查询来为父查询提供查询条件以获得查询结果. 子查询先清除子查询 在清除主查询 ...
- F#周报2019年第7期
新闻 Visual Studio 2019预览版3,F#性能修复 Bolero 0.3发布,HTML模版热加载 Fantomas在线升级至Fantomas 2.9.2 使用F#开发的随机访问Excel ...