多线程之创建线程池
直接new出来,使用ThreadPoolExecutor
查看源码,可以看到,这个类有4个构造方法
这里我们挑最复杂的一个讲解一下各个参数的含义,先看源码
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
- corePoolSize : 核心池的大小,在创建后,如果我们没有调用prestartAllCoreThreads()或prestartCoreThread()这两个预创建线程的方法,那么线程池中是没有线程的,直到有任务来才会有建立线程去执行,如果线程数达到了核心池的大小,就会把任务放到队列中去执行
- maximumPoolSize :最大线程数,当线程数达到了核心池的大小,并且,队列满了,注意,一定是队列满了才会新开线程取执行任务,此时线程池中线程的个数是大于核心池大小的。当线程池中线程个数等于最大线程数时,并且队列也满了,这时候会根据饱和策略RejectedExecutionHandler拒绝新的任务。
- keepAliveTime : 线程保持存活的时间,也就是一个线程在多久没有执行任务的情况下会自动销毁。默认情况下,当线程个数大于核心池大小的时候,才会触发这个属性,一直到线程个数不超过核心池大小。比如核心池是10,现在空闲线程有15个,那么会将线程降到10个,才停止。但是,有一个allowCoreThreadTimeOut(boolean)方法,如果调用这个方法,就不会管核心池大小,比如核心池是10,现在空闲线程有15个,会一直降到0;比如核心池是10,现在空闲线程有8个,也会一直降到0。
unit : 时间的单位:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒workQueue :阻塞队列:常用的有3种:
1)ArrayBlockingQueue:先进先出,基于数组结构,创建时必须指定大小;
2)LinkedBlockingQueue:先进先出,基于链表,如果创建时没有指定队列大小,则默认为Integer.MAX_VALUE,2^31 - 1;
3)synchronousQueue:不保存提交的任务,而是直接新建一个线程来执行新来的任务。
- threadFactory:线程工厂,只是用来生产线程的,实际意义不大,默认的就行。
handler :拒绝策略:
1)ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
2)ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
3)ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
4)ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
我们写个demo看一下如何new一个线程池
public static void main(String[] args) throws Exception{
ThreadPoolExecutor executor = new ThreadPoolExecutor(
//核心线程数5个,最大线程数10个,活跃时间30,单位秒
5, 10, 30, TimeUnit.SECONDS,
// 数组堵塞队列,大小为100
new ArrayBlockingQueue<>(100),
//线程工程
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
return thread;
}
},
// 拒绝策略
new ThreadPoolExecutor.DiscardPolicy());
}
当使用结束后,调用方法关闭线程池,这里提供了两个方法
1)shutdown():不会立即终止线程池,要等所有堵塞队列中的任务都执行完后才终止,此时无法再往队列中加入新任务
2)shutdownNow():立即终止线程池,并尝试终止正在执行的任务,清空堵塞队列,有返回值,是尚未执行的任务
使用Executors类中提供的静态方法创建线程池
先看源码,,一共提供了以下的静态方法,其实看源码,本质还是调用的第一种方法,但是已经封装好了,这里java官方文档建议我们使用这种方法创建线程池,因为简单,不容易出错。
我们先说几个常用的。具体内容以后慢慢补充
- newCachedThreadPool : 创建一个可缓存的线程池
- newWorkStealingPool :以后补充
- newFixedThreadPool :定长线程池,超出线程在队列中等待
- newScheduledThreadPool : 定长线程池,用于定时及周期性任务执行
- newSingleThreadExecutor : 单线程线程
还没有评论,来说两句吧...