java提供的线程池
1、ExecutorService exeThread = Executors.newCachedThreadPool(); // 核心线程数为空 最大线程数量没有上限,没有存储性质的阻塞队列,它的取值操作和放入操作必须是互斥的
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
2、ExecutorService exeThread2 = Executors.newFixedThreadPool(1); //核心线程数等于最大线程数,所有线程都是核心线程(非核心线程数 = 最大线程数 - 核心线程数),采用无参数的链表阻塞队列,最大的任务数可达232-1个。因此存在任务积压导致内存溢出的风险
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
3、ExecutorService exeThread3 = Executors.newSingleThreadExecutor();//只有一个核心线程,无限长的队列
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
推荐手动创建线程池ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, //核心线程数
int maximumPoolSize, //最大线程数
long keepAliveTime, // 最大空闲时间
TimeUnit unit, //时间单位
BlockingQueue workQueue, // 阻塞队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler //拒绝策略
) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
prestartAllCoreThreads();
}
参数
1、int corePoolSize 核心线程数
线程池维护的最小线程数量,核心线程创建后不会被回收(注意:设置allowCoreThreadTimeout=true后,空闲的核心线程超过存活时间也会被回收)。
大于核心线程数的线程,在空闲时间超过keepAliveTime后会被回收。
线程池刚创建时,里面没有一个线程,当调用 execute() 方法添加一个任务时,如果正在运行的线程数量小于corePoolSize,则马上创建新线程并运行这个任务。
2、int maximumPoolSize最大线程数注:(非核心线程数 = 最大线程数 - 核心线程数)
线程池允许创建的最大线程数量。
当添加一个任务时,核心线程数已满、阻塞已满、最大线程数还未到最大,并且没有空闲线程,会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。
3、long keepAliveTime最大空闲时间
当一个可被回收的线程的空闲时间大于keepAliveTime,就会被回收
设置allowCoreThreadTimeout=true后,空闲的核心线程超过存活时间也会被回收
4、TimeUnit unit时间单位
TimeUnit.NANOSECONDS
TimeUnit.MICROSECONDS
TimeUnit.MILLISECONDS // 毫秒
TimeUnit.SECONDS //秒
TimeUnit.MINUTES //分
TimeUnit.HOURS //时
TimeUnit.DAYS //天
5、BlockingQueue workQueue 阻塞队列
常用的阻塞队列表格
workQueue | 描述 |
---|---|
ArrayBlockingQueue | 数组型阻塞队列:数组结构,初始化时传入大小,有界,FIFO,使用一个重入锁,默认使用非公平锁,入队和出队共用一个锁,互斥; |
LinkedBlockingQueue | 链表型阻塞队列:链表结构,默认初始化大小为Integer.MAX_VALUE,有界(近似无解),FIFO,使用两个重入锁分别控制元素的入队和出队,用Condition进行线程间的唤醒和等待; |
SynchronousQueue | 同步队列:容量为0,添加任务必须等待取出任务,这个队列相当于通道,不存储元素; |
PriorityBlockingQueue | 优先阻塞队列:无界,默认采用元素自然顺序升序排列; |
DelayQueue | 延时队列:无界,元素有过期时间,过期的元素才能被取出; |
6、ThreadFactory threadFactory,线程工厂
7、RejectedExecutionHandler handler 拒绝策略
策略 | 描述 |
---|---|
AbortPolicy | 该策略是线程池的默认策略。使用该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常 |
DiscardPolicy | 这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常 |
DiscardOldestPolicy | 这个策略从字面上也很好理解,丢弃最老的。也就是说如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列 |
CallerRunsPolicy | 使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行。 |
自定义 | 如果以上策略都不符合业务场景,那么可以自己定义一个拒绝策略,只要实现RejectedExecutionHandler接口,并且实现rejectedExecution方法就可以了 |
线程池执行流程
线程池运行
线程池运行有两种提交方式
1、execute()方法
execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功
2、submit()方法
submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且通过futrue的get() 方法来获取返回值,get() 方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线 程一段时间后立即返回,这时候有可能任务没有执行完。