Java多线程(⼗三)Java创建线程池,参数详解
Java线程池
⼀、前⾔
对Java开发来说,线程池是⼯作中经常⽤到的⼯具,掌握线程池技术是成为⼀名合格Java程序员的必要条件。
⼆、为什么使⽤线程池?
Java编程中,常创建线程去执⾏需要异步执⾏的功能,如果这些功能很多,不停的创建线程然后销毁线程,是否⾮常消耗资源的。
项⽬中⽤MySQL时,通常会配置⼀个数据源连接池,例如Durid。执⾏⼀条SQL时会⽤到连接池⾥的⼀条连接,执⾏完会还给连接池。Java线程池的思想,我感觉和上⾯连接池很像,是避免反复创建线程对象的⾼开销,从⽽提⾼效率。
三、线程池的基础概念
1. 最⼤线程数
说到线程池,⾸先你得有个抽象的概念,它像⼀个⽔池。那⼀个⽔池,它肯定有⼤⼩,或者说深度,因为⽆限深的⽔池不存在的。
那么Java线程池同理,它也得设置⼀个⼤⼩,否则线程⽆限创建,内存和CPU都会消耗100%。
最⼤线程数它就是指线程池最⼤能创建的线程数量。
在ThreadPoolExecutor类中,最⼤线程数是maximumPoolSize属性。
2. 核⼼线程数
核⼼线程数是ThreadPoolExecutor类中corePoolSize属性。
上⾯已经说了,线程池中最⼤的线程数是maximumPoolSize属性。
默认设置下,创建线程池后,线程池中线程数量=0,每来⼀个任务时,线程池中会创建⼀个线程来执⾏该任务。
当已创建线程数 < corePoolSize时,即使此时线程池中存在空闲线程,也会创建新线程,这些线程称为核⼼线程。
当已创建线程数 == corePoolSize时,⼜有任务来,会把任务放到阻塞队列中排队。
当阻塞队列已满,且已创建线程数<maximumPoolSize,创建⾮核⼼线程执⾏任务。
当阻塞队列已满,且已创建线程数==maximumPoolSize,使⽤拒绝策略。
核⼼线程数 + ⾮核⼼线程数 = 最⼤线程数
所以设置线程池时,要设置corePoolSize、maximumPoolSize这2个参数。
因为通过计算:⾮核⼼线程数 = maximumPoolSize - corePoolSize
注意:上⾯公式的背景是任务超多,已创建线程数达到maximumPoolSize了。
如果 corePoolSize < 已创建线程数 < maximumPoolSize,也就是线程池还没到上限。
那么:⾮核⼼线程数 = 已创建线程数 - corePoolSize
下⾯看下线程池的流程图,可以更好的理解corePoolSize和maximumPoolSize属性。
3. 线程存活时间
线程存活时间是ThreadPoolExecutor类中keepAliveTime和unit这2个属性共同设置。
keepAliveTime是时间⼤⼩,⽽unit是单位(天、⼩时、分钟、秒、毫秒、微妙、纳秒)
默认当线程池中已创建线程数 > corePoolSize时,keepAliveTime才会起作⽤。
即⼀个空闲线程存活到keepAliveTime了,就会被销毁,直到已创建线程数== corePoolSize。
但是如果设置allowCoreThreadTimeOut(true)时,已创建线程数<= corePoolSize,keepAliveTime也会起作⽤。
4. 阻塞队列
阻塞队列是ThreadPoolExecutor类中workQueue属性。
⼀个阻塞队列,⽤来存储等待执⾏的任务,这个参数会对线程池的运⾏过程产⽣重⼤影响,⼀般来说,这⾥的阻塞队列有以下⼏种选择:
1. ArrayBlockingQueue : 有界的数组队列
2. LinkedBlockingQueue : 可⽀持有界/⽆界的队列,使⽤链表实现
3. PriorityBlockingQueue : 优先队列,可以针对任务排序
4. SynchronousQueue : 队列长度为1的队列,和Array有点区别就是:client thread提交到block queue会是⼀个阻塞过程,直到有
⼀个worker thread连接上来poll task。
ArrayBlockingQueue和PriorityBlockingQueue使⽤较少,⼀般使⽤LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
5. 拒绝策略
拒绝策略是ThreadPoolExecutor类中handler属性。
拒绝策略表⽰当拒绝处理任务时的策略,有以下四种取值:
1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
2. ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前⾯的任务,然后重新尝试执⾏任务(重复此过程)
4. ThreadPoolExecutor.CallerRunsPolicy:由调⽤线程处理该任务
java线程池创建的四种四、Executors⼯具类创建线程池
在学线程池时,教材和博客上⼀般都会介绍Executors⼯具类下⾯的⼏种Java已经实现的线程池。
下⾯定义⼀个任务类:
public class MyWorker implements Runnable {
private Integer num;
public MyWorker(){
}
public MyWorker(Integer num){
this.num = num;
}
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"正在执⾏,数值:"+ num);
try{
//假装⼯作1秒
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
1. 可变数量 newCachedThreadPool
创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。
public class Thread01_NewCached_Runnable {
public static void main(String[] args){
ExecutorService executorService = wCachedThreadPool();
for(int i=1; i<=100; i++){
executorService.submit(new MyWorker(i));
}
executorService.shutdown();
}
}
运⾏结果:
pool-1-thread-1正在执⾏,数值:1
pool-1-thread-2正在执⾏,数值:2
。。。。。。
pool-1-thread-98正在执⾏,数值:98
pool-1-thread-99正在执⾏,数值:99
pool-1-thread-100正在执⾏,数值:100
从结果可见线程池创建了100个线程来执⾏任务,返回结果也⾮常快。
我们来看newCachedThreadPool的定义:
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
属性newCachedThreadPool的值corePoolSize0
maximumPoolSize Integer.MAX_VALUE
keepAliveTime60
unit TimeUnit.SECONDS workQueue SynchronousQueue
threadFactory defaultThreadFactory handler AbortPolicy
2. 固定数量 newFixedThreadPool
创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。
public class Thread03_NewFixed_Runnable {
public static void main(String[] args){
//固定⼤⼩=3的线程池
ExecutorService executorService = wFixedThreadPool(3);
for(int i=1; i<=100; i++){
executorService.submit(new MyWorker(i));
}
executorService.shutdown();
}
}
运⾏结果
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论