博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中线程池的使用(ThreadPoolExecutor)
阅读量:6694 次
发布时间:2019-06-25

本文共 2703 字,大约阅读时间需要 9 分钟。

一.为什么使用线程池:

1.降低资源消耗。主要指的是降低创建和销毁线程时产生的cpu资源消耗,线程池通过持续工作的线程执行不断分配的新任务,来减少频繁的线程创建与销毁。

##2.提高响应速度。同上

##3.提高线程的可管理性。线程是稀缺资源,频繁的创建销毁,以及没有控制的大量创建,都会影响系统的稳定性。使用线程池可以统一分配,调优,监控资源。

二.如何创建线程池:

new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler);

corePoolSize:

线程池的基本大小,即在没有任务需要执行的时候线程池中运行的线程数量。只有在工作队列满了的情况下才会创建超出这个数量的线程。

相关1:

刚刚创建ThreadPoolExecutor的时候,线程并不会 立即启动,而是要等到有任务提交时才会启动。如果预先调用了prestartCoreThread()/prestartAllCoreThreads(),则会事先启动核心线程。

相关2:

考虑到keepAliveTime()和allowCoreThreadTimeOut()超市参数的影响,没有任务或者没有足够任务执行的时候,线程池中运行线程的数量(线程池的大小)小于等于corePoolSize。

maximumPoolSize:

线程池中允许的最大线程数,线程池中的当前运行线程数不会超过这个值,为了保证系统资源有控制的消耗。

相关1:

由于maximumPoolSize可以在运行中通过setMaximumPoolSize()来设置,所以可以通过largestPoolSize()方法来获得线程池曾经运行过的最大线程数量,来评估当前maximumPoolSize设置是否合适。

keepAliveTime:

当线程空闲后,保留的时间。用来在任务不繁忙的时候减少运行线程数量。在单任务时间较短,任务请求较频繁的情况下,可以适当延长保留存活时间来减少系统创建和销毁线程的开销。

相关1:

对于核心线程,默认一直保留存活,如果将allowCoreThreadTimeOut设置为true,则核心线程也接受keepAliveTime的约束。

TimeUnit unit:

用来修饰keepAliveTime的时间单位,可以为纳秒,毫秒,秒,分,小时,天等TimeUnit中的静态常量。

BlockingQueue:

线程安全的队列,用来存放排队的任务。

相关1:

此BlockingQueue的实现有:

->ArrayBlockingQueue:基于数组结构的有届阻塞队列,FIFO
->LinkedBlockingQueue:基于链表的阻塞队列,FIFO。吞吐量大于上者。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
->SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于LinkedBlockingQueue.静态工厂方法Executors.newCachedThreadPool()使用了这个队列。
->PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

ThreadFactory:

用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

RejectedExecutionHandler:

当队列和线程池都满了之后的饱和策略。默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略:

->AbortPolicy:直接抛出异常
->CallerRunsPolicy:只用调用者所在的线程来运行任务。
->DiscardOldestPolicy:丢弃队列里最近一个任务,并执行当前任务。
->DiscardPolicy:不处理,丢弃掉。
->也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

三.如何调用线程池:

1.通过execute(Runnable run)方法来执行任务:

threadsPool.execute(new Runnable(){

@overridepublic void run(){    //code to run.}

});

但是execute()方法没有返回值,无法获得任务执行的情况信息。

2.通过submit()方法来提交执行任务:

Future future=executor.submit(harReturnValueTask);

try{

Object o=future.get();

}catch(Exeception e){

}finally{

executor.shutdown();

}

submit()方法会返回一个future对象,通过future的get()方法,可以获得任务执行情况。get()方法会阻塞直到任务执行完毕。也可以使用get(long timeout, TimeUnit unit)来设置最长阻塞时间。

如何关闭线程池:

我们可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。但是它们存在一定的区别,shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。

今天困了,先写到这里,主要参考文章:

转载地址:http://wojoo.baihongyu.com/

你可能感兴趣的文章
利用vue-cli配合vue-router搭建一个完整的spa流程(一)
查看>>
Microsoft推出适用于Win 8.1和Win10的KB 4010250 Flash Player更新
查看>>
JS的内置对象系列:Array(一)
查看>>
微软宣布开源WPF、WinForms和WinUI
查看>>
携程对AIOps场景和算法的探索与实践
查看>>
AlphaZero进化论:从零开始,制霸所有棋类游戏
查看>>
OpsRamp推出AIOps推理引擎
查看>>
webpack使用之基础篇
查看>>
如何避免if else
查看>>
android团队对新技术的态度
查看>>
『.NET Core CLI工具文档』(十)dotnet-build
查看>>
AngularJS中$q的promise使用及链式调用传值问题
查看>>
Scala Essentials: 类型约束
查看>>
JS异步那些事 二 (分布式事件)
查看>>
技术团队代码管理和部署
查看>>
Swift 项目主管和大家聊了聊 Swift 5,ABI 稳定性最受关注
查看>>
mybatis 插件 flying-清明 发布
查看>>
Java实现excel导入导出学习笔记2 - 利用xml技术设置导入模板,设置excel样式
查看>>
NG-ZORRO-MOBILE 0.11.5 发布,基于 Angular 7 的 UI 组件
查看>>
The Little JavaScript Closures
查看>>