为什么会存在线程池
线程池是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度,因此存在线程池来解决一些问题。
如何创建一个线程池
Java中已经提供了创建线程池的一个类:Executor,我们一般用它的子类ThreadPoolExecutor 来创建线程池
线程池的类的继承关系
public class ThreadPoolExecutor extends AbstractExecutorService
通过源码我们可以看出ThreadPoolExecutor 继承AbstractExecutorService 抽象类
线程池存在哪些接口,都提供了哪些方法,有什么作用
//线程状态
volatile int runState;
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
//阻塞队列
private final BlockingQueue<Runnable> workQueue;
//互斥锁
private final ReentrantLock mainLock = new ReentrantLock();
//终止条件
private final Condition termination = mainLock.newCondition();
//线程集合,一个worker 对象为一个线程
private final HashSet<Worker> workers = new HashSet<Worker>();
//空闲状态
private volatile long keepAliveTime;
//表示是否允许“线程在空闲状态时,仍能够存活”
private volatile boolean allowCoreThreadTimeOut;
//核心池大小
private volatile int corePoolSize;
//最大池大小
private volatile int maximumPoolSize;
//当前大小
private volatile int poolSize;
//拒绝处理任务时的策略
private volatile RejectedExecutionHandler handler;
//线程工厂
private volatile ThreadFactory threadFactory;
//记录之前线程最大时的大小
private int largestPoolSize;
//完成线程的数量
private long completedTaskCount;
//默认处理器。抛出异常
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
ThreadPoolExecutor 构造参数有哪些?分别什么意思
ThreadPoolExecutor 有四个构造方法,但其实前三个构造方法都调用的是第四个构造器
public ThreadPoolExecutor(int corePoolSize,//核心线程数量
int maximumPoolSize,//最大线程数量
long keepAliveTime,//超出核心线程以外线程的存活时间
TimeUnit unit,//参数keepAliveTime的时间单位
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:核心线程数
maximumPoolSize:最大线程数
keepAliveTime
表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize
但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
unit:keepAliveTime 的单位,
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue:阻塞队列。
threadFactory:线程工厂,用来创建线程。
handler: 当任务被拒绝时的策略。
Executors静态工厂几种常用线程池
ewFixedThreadPool()方法:该方法返回一个固定线程池数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲的线程,则立即执行。若没有,则新的任务会被暂存到一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
newSingleThreadExecutor()方法:该方法返回一个只有一个线程的线程池。若多余一个任务被提交到线程池,任务会被保存到一个任务队列里中,待线程空闲,按先入先出的顺序执行队列中的任务。
newCachedThreadPool()方法:该方法返回一个可根据实际情况调整线程数量的线程池。线程池的数量不确定,但若有空闲可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完成后,将返回线程池进行复用。
newSingleThreadSchduledExecutor() 方法:该方法返回一个ScheduledExecutorService对象,线程池的大小为1,ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能,如在某个固定的延时之后执行,或者周期性执行某个任务。
newScheduledThreadPool()方法:该方法返回一个ScheduledExecutorService对象,但该线程池可以指定线程数量。