目录
2.6 ThreadFactory threadFactory:
2.7 RejectedExecutionHandler handler:
2.1 newFixedThreadPool(int nThreads):创建固定线程池
2.2 newSingleThreadExecutor():创建单线程
2.3 newCachedThreadPool():创建可缓存线程池
2.4 newScheduledThreadPool(int corePoolSize):创建定时执行线程池
1.创建线程池
1.第一种方式:ThreadPoolExecutor类
1.ThreadPoolExecutor类的源码
概念:是线程池的实现类,使用类的构造器来创建线程
源码:
public ThreadPoolExecutor(
//核心线程数
int corePoolSize,
//最大线程数
int maximumPoolSize,
//线程存活时间
long keepAliveTime,
//存活时间单位:通常是Seconds
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;
}
2.ThreadPoolExecutor类的源码的参数
2.1 int corePoolSize:
核心线程数,代表了处理线程时的核心运行线程数量(任务队列此时是没有存满的)
2.2 int maximumPoolSize:
最大线程数,当任务队列存满了,同时运行的线程数量大于核心线程数,此时代表的是最大线程数量
这二者的区别:一般任务队列没存满,就用corePoolSize;任务队列存满后仍有线程任务,此时就需要用到maximumPoolSize,创建非核心线程处理任务
2.3 long keepAliveTime:
线程存活时间,线程未处理任务的最大存活时间,超过这个时间就回收线程
2.4 TimeUnit unit:存活时间单位:
通常是keepAliveTime的单位,比如TimeUnit.Seconds
2.5 BlockingQueue<Runnable> workQueue:
任务队列,当运行线程的数量达到corePoolSize,则将任务存放在任务队列中
2.6 ThreadFactory threadFactory:
线程工厂,用来创建新线程
2.7 RejectedExecutionHandler handler:
拒绝策略,当任务队列workQueue已满,且正在运行的线程数达到了最大线程数maximumPoolSize,此时需要对新任务根据策略进行处理;
常用的拒绝策略:
2.7.1 AbortPolicy:中止策略;直接抛出异常
2.7.2 DiscardPolicy:丢弃策略;将新任务丢弃
2.7.3 DiscardOldestPolicy:丢弃最旧策略;丢弃最旧的任务请求
2.7.4 CallerRunsPolicy:调用方运行策略;调用当前线程运行新任务
2.第二种方式:Executors工具类
1.Executors工具类的源码
概念:是一个工具类,定义了许多创建线程池的方法
源码:Executors工具类中声明的方法有:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
2.Executors工具类源码的方法
2.1 newFixedThreadPool(int nThreads):创建固定线程池
处理任务时,先判断是否有空闲线程,没有则放到任务队列,有则直接执行
2.2 newSingleThreadExecutor():创建单线程
处理任务时,判断该单线程是否空闲,不空闲则放到任务队列,空闲就直接执行
2.3 newCachedThreadPool():创建可缓存线程池
处理任务时,若有空闲线程,则使用空闲线程处理任务;若没有空闲线程,则创建新的线程处理任务,处理完毕缓存到线程池
2.4 newScheduledThreadPool(int corePoolSize):创建定时执行线程池
该线程池能够定期执行任务或者延迟执行任务;一般都不会用到
3.创建线程池方法的选择
一般使用ThreadPoolExecutor类来创建线程池
原因:与任务队列有关
1.任务队列的分类
SynchronousQueue:同步队列(无界);不存储元素,队列直接提交给线程执行:
若有空闲线程,则使用空闲线程来处理
没有空闲线程,则新建一个线程来处理任务
存在问题:会创建大量线程,产生Out Of Memory错误
LinkedBlockingQueue:无界对列;当线程池线程数达到最大数量,新任务就会在队列中等待执行
存在问题:可能会造成队列无限膨胀
ArrayBlockingQueue:有界队列;有助于防止资源耗尽
存在问题:一旦达到上限,可能会造成新任务丢失
2. Executors工具类的方法中使用的任务队列
newFixedThreadPool:LinkedBlockingQueue;会造成队列无限膨胀
newSingleThreadExecutor:LinkedBlockingQueue;会造成队列无限膨胀
newCachedThreadPool:SynchonousQueue;会创建大量线程
newScheduledThreadPool:DelayedWorkQueue;队列存满后会自动扩容,造成队列无限膨胀
综上:由于Executors工具类的方法中使用的任务队列会产生种种资源浪费问题,通常采用ThreadPoolExecutor类来创建线程池
2.线程池执行过程
处理任务时:
- 若当前运行的线程数小于核心线程数,则新建一个线程处理该任务;
- 若当前运行的线程数大于等于核心线程数,但小于最大线程数,则将任务存放到任务队列
- 若任务队列已满,但当前运行线程数小于最大线程数,则新建一个线程处理任务
- 若任务队列已满,且当前运行线程数大于最大线程数,则根据拒绝策略处理该任务
- 若任务队列已满,但当前运行线程数小于最大线程数,则新建一个线程处理任务