java自带线程池的使用
2017-06-17 11:52
295 查看
线程池简介
线程池技术一是用以控制系统中线程的数量,使得线程数不因太少而浪费资源,不因太多而导致效率不高(线程的创建和销毁都需要占用时间、资源)。jdk1.4之前的版本中,线程池都极其简陋,jdk1.5之后引入了java.util.current之后,情况开始大幅改观。为我们解决线程问题提供了很大的便利。
java中线程池的接口
最顶级的接口是Excutors,但严格意义上说,Excutors并不是线程池,只是线程执行的工具,真正的线程池接口是ExcutorService。我们列出jdk中常用的一些有关线程池的类1. newSingleThreadExecutor
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2. newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
3. newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
4. newScheduledThreadPool
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
ThreadPoolExcutor详解
ThreadPoolExcutor的构造方法的完整参数是ThreadPoolExcutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workingQueue,ThreadFactory threadFactory,RejectedExcutionHandler handler) /** *corePoolSize 线程池中保留的线程,包括闲置线程 *maximumPoolSize 线程池中允许的最大线程数 *keepAliveTime 当线程数大于核心数时,这是空闲线程等待新任务的最大时间 *unit -keepAliveTime的时间单位 *workingQueue 执行前用于保持任务的队列,此队列仅保持由excute()提交的Runnable任务 *threadFactory 执行程序创建新线程的工厂 *handler 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序 */
ThreadPoolExcutor是Excutors类的底层实现。
下面看下各类关于它的具体实现
public static ExcutorService newFixedThreadPool(int nThreads){ return new ThreadPoolExcutor(nThreads,nThreads, 0L,TimeUnit.MILLIONSECONDS, new LinkedBlockingQueue<Runnable>); }
在这里,corePoolSize和maximumPoolSize相等,keepAliveTime为0,LinkedBlockingQueue是无界的。
而单线程池
public static ExcutorService newSingleThreadExcutor(){ return new ThreadPoolExcutor(1,1, 0L,TimeUnit.MILLIONSECONDS, new LinkedBlockingQueue<Runnable>); }
newCachedThreadPool的实现
public static ExcutorService newCachedThreadPool(){ return new ThreadPoolExcutor(0,Integer.MAX_VALUE, 60L,TimeUnit.MILLIONSECONDS, new SynchronousQueue<Runnable>) }
关于BlockingQueue
所有的BlockingQueue都可以用于传输和保持提交的任务,可以使用此队列和池大小进行交互:如果运行的线程少于线程池的corePoolSize,那么Excutor始终优先选择添加新的线程,而不进行排队;
如果线程数大于或者等于线程池的corePoolSize,那么优先选择进入队列,而不添加线程;
如果无法请求加入队列,则创建新的线程,除非线程数超过maximumPoolSize,这种情况下,任务会被拒绝。
排队的策略
直接提交:任务队列的默认选项是SynchronousQueue,它将任务直接提交给线程而不是保持它们。因此,如果不存在直接运行任务的线程,则试图将任务加入队列失效,因此会创建一个新的线程。此策略可以避免在处理具有内部依赖性的请求集时出现锁。直接提交应该要求无界maximumPoolSize以免拒绝任务提交。当命令以超过队列所能处理的平均数到达时,此策略允许无界线程线程具有增长的可能性。无界队列:使用无界队列(例如不具有预定义容量的LinkedBlockingQueue)将导致所有corePoolSize线程都忙时新任务处在等待状态。这样创建的线程就不会超过corePoolSize,那么maximumPoolSize也就没有意义了。当每个任务之间相互独立时,适合于使用无界队列。当命令以超过队列处理的平均数到达时,此策略允许无界线程具有增长的可能性。
有界队列:当时用有界的maximumPoolSize时,使用有界队列(ArrayBlockingQueue)有助于避免资源的耗尽,但是较难调整和控制,队列大小和最大池大小可能需要相互折中:使用最大队列和小型池可以最大限度的降低CPU使用率,操作系统资源以及上下文切换的开销。但是可能也人工的造成了吞吐量的下降,使用小型池和大队列,则有可能增大了CPU的使用,但是又造成了不可接受的调度开销,同样会降低吞吐量。
相关文章推荐
- Java 自带四种线程池的使用
- Java_多线程_创建和使用Java自带的线程池
- java自带线程池和队列详细讲解(Java线程池使用说明)
- 介绍 Java 自带的线程池(1)
- Java自带的Logger使用-代码摘要
- Java四种线程池的使用
- java多线程--线程池的使用
- 使用java自带的定时任务ScheduledThreadPoolExecutor
- 【转载】Java并发编程13:线程池的使用
- java多线程CountDownLatch及线程池ThreadPoolExecutor/ExecutorService使用示例
- java并发:线程池的分析和使用
- new Thread的弊端及Java四种线程池的使用
- java使用默认线程池踩过的坑(二)
- Java 线程池(ThreadPoolExecutor)原理分析与使用
- java自带线程池和队列详细讲解
- Java四种线程池的使用
- 聊聊并发(三)Java线程池的分析和使用
- java自带线程池和队列详细讲解
- Java四种线程池的使用
- Java四种线程池的使用