线程池总结
来源:互联网 发布:网络高清图片 编辑:程序博客网 时间:2024/06/06 05:33
线程池实现原理
当提交一个新的任务之后,线程池的处理如下: 1)判断核心线程池是否已经满了,如果没有满,则创建一个新的工作线程来执行任务。如果核心线程池都在执行任务,则进入下一个步骤 2)线程池判断工作队列是否已经满了。如果工作队列没有满,则将新提交的任务提交到这个工作队列中,若工作队列满了,则进入下一个流程。 3)线程池判断线程池是否都处于工作状态。如果没有,则创建一个新的线程来执行这个任务。如果已经满了,则交给饱和策略来处理这个任务。
工作图
ThreadPoolExecutor执行execute方法分下面四种情况
1)如果当前运行运行的线程少于corePoolSize,则创建新的线程来执行任务
2)如果运行的线程等于或者多余corePoolsize,则将任务加入BlockingQueue。
3)如果无法将任务加入BlockingQueue(队列已经满了),则创建新的线程来处理任务。
4)如果创建新的线程使得当前运行的线程超出maximumPoolSize,任务将被拒绝。
在ThreadPoolExecutor完成预热之后,几乎所有的方法都是执行步骤2,而步骤2不需要获取全局锁。
源码分析
public void execute(Runnable command){ if(command == null) throw new NullPointException(); //如果线程数小于基本线程数,则创建线程并且执行 if(poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)){ //如果线程数大于等于基本线程数或者线程数创建失败,则将当前任务放在工作队列中 if(runState == RUNNING && workQueue.offer(command)){ if(runState != RUNNING || poolSize == 0) ensureQueuedTaskHandled(command); }else if(!addIfUnderCorePoolSize(command)){ reject(command); } }}
工作线程:线程池创建线程时候,会将线程封装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行。
public void run(){ try{ Runnable task = firstTask; firstTask = null; while(task != null ||(task = getTask()) != null){ runTask(task); task = null; } }finally{ workDone(this); }}
线程池执行线程分为两种情况:
1)在execute()方法创建一个线程时候,会让这个线程执行当前任务
2)创建的线程执行完任务后,会反复从BlockingQueue获取任务执行
线程池的使用
线程池的创建
我们可以通过ThreadPoolExecutor(corePoolsize, maximunPoolSize, keepAliveTime, millseconds, runnableTaskQueue, hadnler)
corePoolSize:当提交一个任务到线程池时候,线程池会创建一个线程执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的线程数线程池的基本大小的时候就不在创建。
RunnableTaskQueue:任务队列,用于保存等待执行的任务的阻塞队列。可以选择一下几个阻塞队列:
ArrayBlokingQueue:是一个基于数组的有界的阻塞队列,此队列按照先进先出原则对元素进行排序。LinkedBlockingQueue:一个基于链表结构的阻塞队列。Executors.newFixedThreadPool()使用了这个队列。SynchronousQueue:一个不存储元素的阻塞队列。每个的插入操作必须等待另一个线程的移除操作,否在插入操作一直处于阻塞状态。静态方法Executors.newCachedThreadPool使用了这个队列
maximunPoolSize:线程池允许创建的最大线程数。如果队列满了,并且已经创建的线程数小于最大线程数,则继续创建线程执行任务。
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采用·一种策略来处理,JDK使用以下几种策略:
AbortPolicy:直接抛出异常
CallerRunsPolicy:只用调用者所在的线程来执行人物
DiscardOldestPolicy:丢弃队列里的最近的一个任务,来执行当前任务
DiscardPolicy:不处理,丢弃。
KeepAlive:线程池工作线程空闲后,保持存活的时间。
TimeUnit:存活时间单位
向线程池提交任务
可以使用两个方法来向线程池提交任务,分别是execute()和submit()方法。
execute()用来提交不需要返回值的方法
threadPool.execute(new Runnable(){ public void run(){ //.... }});
submit()用来提交需要返回值的任务。线程池返回一个Future对象,通过这个Future对象可以判断任务是否执行成功,可以通过Future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,使用get(long timeout, TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
Future<Object> future = excutor.submit(...);Object s = future.get();
关闭线程池
可以通过调用线程池的shutdown或者shutdowNow方法来关闭线程池。他们的原理是遍历线程池中的每个线程,调用线程的interrupt方法来中断线程。shutdownNow首先将线程池状态设置为stop,然后尝试终止正在执行或者或者暂停任务的状态,并且返回等待任务的列表,不能确保任务执行完。shutdown:将线程池状态设置为shutdown状态,然后中断所有没有正在执行任务的线程,确保任务执行完。
- 线程、线程池总结
- 【面试】线程/线程池总结
- 线程、多线程、线程池总结
- Java线程池总结
- Java线程池总结
- 线程池总结
- Java线程池总结
- 线程池的总结
- 线程池总结
- Java线程池总结
- 线程池总结
- 线程池的总结
- MySQL线程池总结
- Java线程池总结
- 线程池知识总结
- 线程池相关总结
- Java线程池总结
- 多线程---线程池总结
- Spring MVC 文件上传下载
- idm安卓版(手机下载软件)中文专业版V5.0下载 | Android IDM+ v5.0
- Cube-web系统之Quartz+Spring实现任务监控管理
- SlinkList(不带头节点的单链表)20171003
- 最大数max(x,y,z)
- 线程池总结
- Mysql修改数据库密码
- 【简单易上手】虚拟机及win XP系统安装经验
- jq代码学习----文本框得到失去焦点
- 文字溢出隐藏显示省略号
- 阿里云服务器ECS Ubuntu16.04-64-bit学习之一:配置桌面
- python之Web Server Gateway Interface
- cookie,localStorage,sessionStorage
- 什么是跨域?怎么解决跨域问题?