一、什么是线程池
线程池和和字符串常量池, 数据库连接池一样, 都是为了提高程序的运行效率, 减少开销; 随着并发程度的提高, 当我们去频繁的创建和销毁线程, 此时程序的开销还是挺大的, 为了进一步提高效率, 就引入了线程池, 程序中所创建的线程都会加载到一个 “池子” 中, 当程序需要使用线程的时候, 可以直接从池里面获取, 用完了就将线程还给池, 这样在多线程的环境中就不用去重复的创建和销毁线程, 从而使程序的运行效率提高, 线程池是管理线程的方式之一.
Java中提供了线程池相关的标准类ThreadPoolExecutor, 也被称作多线程执行器, 该类中的线程包括两类, 一类是核心线程, 另一类是非核心线程, 当核心线程都被占用还不能满足程序任务执行的需求时, 就会启用非核心线程, 直到任务量少了, 随之非核心线程也就会销毁.
public static class testPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
二、线程池的原理
Executors类提供4个静态工厂方法:newCachedThreadPool()、newFixedThreadPool(int)、newSingleThreadExecutor和newScheduledThreadPool(int)。这些方法最终都是通过ThreadPoolExecutor类来完成的,这里强烈建议大家直接使用Executors类提供的便捷的工厂方法,能完成绝大多数的用户场景,当需要更细节地调整配置,需要先了解每一项参数的意义。
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
配置参数:
corePoolSize——核心线程数。
例如设置为5,默认情况下不会初始化线程,
当程序提交任务总数小于6个时,线程池在收到提交的线程时创建线程。
maximumPoolSize——最大线程数。例如设置为10,则线程池内最多创建10个线程存活。
keepAliveTime,unit——线程数多于核心线程数时,线程被回收前的空闲时间(值和单位)。例如:配置30秒,按以上5,10的示例,当线程池内的线程大于5个时,
有现成空闲时间超过30秒则该线程会被回收。
workQueue——任务队列。当提交的任务需要排队处理时,任务会被放到该队列排队,等待处理。什么时候入队列?当活跃线程数大于等于核心线程数时,操作入队列。
什么时候创建大于核心线程数的线程?
如果队列满了,调用创建线程方法,创建成功则当前任务开始在新线程中运行。
线程数达到上线了怎么办?执行拒绝策略。
threadFactory——线程工厂。
控制线程池中的线程对象的创建,创建线程时设置线程名,是否后台线程。
handler——拒绝策略。当任务既不能加入到线程执行,又不能加入到任务队列时,按此策略处理
默认采用中断策略,抛出异常。
即提交任务需要拒绝时,抛出RejectedExecutionException异常。