corePoolSize核心线程
线程池的基本大小,即在没有任务需要执行的时候线程的大小,并且只有在工作队列满了的情况下才会创建出超出这个数量的线程。
核心线程是否会被回收?
- 核心线程将一直保存在线程池中。
- 哪怕核心线程是处于空闲状态,也可以不回收。
- allowCoreThreadTimeOut参数可以控制是否回收核心线程。
- 在刚刚创建线程池的时候,核心线程并不会立刻启动,而是要等到有任务提交时才会启动。
- prestartCoreThread/prestartAllCoreThread方法可以事先启动核心线程。
阻塞队列
当所有的核心线程处于工作状态时,再向线程池提交任务,将无核心线程可以直接处理。阻塞队列就是保存这些将要被线程池执行的任务的。
阻塞队列注意事项
- BlockingQueue接口的所有子类都可以作为阻塞队列。
- 阻塞队列的容量问题要注意。如果选择无界阻塞队列,即线程池的核心线程都处于工作状态后,线程池将无限制的接收所有的任务,可能会造成阻塞队列过长,影响JVM性能,严重情况下可能会造成OOM。
maximumPoolSize最大线程数
线程池中允许的最大线程数,线程池中所有的线程数目不会超过该值。如果线程池队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。这部分创建出的线程叫做非核心线程。
另外largestPoolSize,该变量记录了线程池在整个生命周期中曾经出现的最大线程个数。之所以是曾经,是因为线程城池创建之后,可以调用setmaximumPoolSize()改变运行的最大线程的数目。
非核心线程是否会被回收?
- 非核心线程是会被回收的。
- keepAliveTimeOut/unit控制非核心线程最大的空闲时间,超过这个时间还没有任务可以执行,非核心线程将会被回收。
线程工厂
线程工厂就是线程池创建线程的工厂,ThreadPoolExecutor使用了Executors提供的默认线程工厂,代码如下:
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
如果有需求或者必要,可以定义自己的线程工厂,只要实现ThreadFactory接口即可,如:
static class NameThreadFactory implements ThreadFactory{
//线程ID
private final AtomicInteger threadId = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r,"线程-" + threadId.getAndIncrement());
System.out.println(t.getName() + " 已经被创建");
return t;
}
}
拒绝策略/饱和策略
当线程池的线程数达到最大,并且阻塞队列的容量也达到了最大的时候,线程池将达到最大负载,此时如果再向线程池中添加任务,线程池将无法继续处理。线程池的拒绝策略就是为了保护线程池的负载。
ThreadPoolExecutor提供了四种拒绝策略:
你也可以通过实现RejectedExecutionHandler来定义自己的拒绝策略。
CallerRunsPolicy
由线程池的调用线程(调用execute方法的线程)执行任务,线程池本身处于饱和状态时不再受理任何外部提交的任务。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
AbortPolicy
通过抛出RejectedExecutionException异常的方式拒绝执行任务。
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
DiscardPolicy
悄悄把任务丢弃,不做任何处理和记录。
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
DiscardOldestPolicy
丢弃队列中最早进入队列的任务,然后再次尝试执行这次提交给线程池的任务。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
自定义拒绝策略
public static class MyIgnorePolicy implements RejectedExecutionHandler{
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
doLog(r,executor);
}
private void doLog(Runnable r, ThreadPoolExecutor executor){
System.err.println(r.toString() + " rejiected");
}
}