介绍
当程序中需要使用异步或提高效率的时候我们需要使用到线程池。
ThreadPoolExecutor
构造参数介绍
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize 核心线程数
- maximumPoolSize 最大线程数
- keepAliveTime 保持存活时间
- unit 保持存活时间单位
- workQueue 任务存储队列
- threadFactory 线程工厂
- handler 拒绝策略
corePoolSize
核心线程数,线程池在被创建后是没有线程的,当一个任务被丢进线程池时,如果线程池的任务数量没有超过核心线程数,那么会创建一个线程work计算当前任务
maximumPoolSize
最大线程数,当一个任务被丢进线程池时,如果核心线程数满了,并且任务队列也满了,并且maximumPoolSize>corePoolSize,那么会创建一个 work 计算当前任务
keepAliveTime,unit
unit是keepAliveTime的时间单位,当线程池中的线程数多与核心线程数(maximumPoolSize-corePoolSize这部分线程),并且这部分线程一直处于等待状态,那么当等待时长超过keepAliveTime这部分线程会被回收
workQueue
任务存储队列,当一个任务被丢进线程池时,如果核心线程数满了并且任务队列没有满,那么这个task会丢进任务队列中等待被计算。
threadFactory
线程工厂,用来生产线程的工厂。一般使用默认的线程池工厂Executors.defaultThreadFactory(),默认的线程池工厂都是在同一个线程组,拥有同样的优先级并且都是守护线程
handler
拒绝策略,当核心线程数满了,并且任务队列也满了,并且最大线程数也满了,这个时候如果在来一个task,那么会执行拒绝策略
拒绝策略
AbortPolicy
抛异常
/**
* A handler for rejected tasks that throws a
* {@code 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());
}
}
CallerRunsPolicy
如果线程池没有被暂停,那么就使用当前线程(往线程池中丢任务的线程)执行
/**
* A handler for rejected tasks that runs the rejected task
* directly in the calling thread of the {@code execute} method,
* unless the executor has been shut down, in which case the task
* is discarded.
*/
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();
}
}
}
DiscardPolicy
丢弃策略,执行将当前任务丢弃
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
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
当线程池没有被暂停的时候,会将任务队列Queue中弹出一个丢弃,并且将当前任务重新丢给线程池
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
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);
}
}
}
添加任务的流程图
coding
代码如下
package pres.bik.lean.concurrent;
import java.util.concurrent.*;
/**
* 线程池参数
*
* @author yangkaifei
* @version 1.0
* @date 2021/11/28 4:52 下午
*/
public class ThreadPoolExecutorLean {
/**
* 核心线程数
*/
private static int CORE_POOL_SIZE = 2;
/**
* 最大线程数
*/
private static int MAXIMUM_POOL_SIZE = 3;
/**
* 存活时间
*/
private static long KEEP_ALIVE_TIME = 60;
/**
* 队列大小
*/
private static int WORK_QUEUE_SIZE = 2;
/**
* 任务存储队列
*/
private static BlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(WORK_QUEUE_SIZE);
/**
* 抛异常策略
*/
private static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.AbortPolicy();
/**
* 线程池
*/
private static ThreadPoolExecutor EXECUTOR_SERVICE = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE_TIME, TimeUnit.SECONDS, WORK_QUEUE, Executors.defaultThreadFactory(), HANDLER);
public static void main(String[] args) {
run();
}
/**
* 线程池参数了解
*/
private static void run() {
int length = MAXIMUM_POOL_SIZE + WORK_QUEUE_SIZE + 2;
for (int i = 1; i < length; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("睡眠被中断");
}
int finalI = i;
try {
EXECUTOR_SERVICE.execute(new Thread(() -> {
System.out.println("============");
System.out.println(String.format("开始执行任务:%s", finalI));
System.out.println(String.format("任务%s活跃线程数:%s", finalI, EXECUTOR_SERVICE.getActiveCount()));
System.out.println(String.format("任务%s队列中的数量:%s", finalI, EXECUTOR_SERVICE.getQueue().size()));
System.out.println("============");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
System.out.println("睡眠被中断");
}
}));
} catch (Exception e) {
System.err.println("执行了异常策略:" + finalI);
}
}
EXECUTOR_SERVICE.shutdown();
}
}
运行结果
============
开始执行任务:1
任务1活跃线程数:1
任务1队列中的数量:0
============
============
开始执行任务:2
任务2活跃线程数:2
任务2队列中的数量:0
============
============
开始执行任务:5
任务5活跃线程数:3
任务5队列中的数量:2
============
执行了异常策略:6
============
开始执行任务:3
任务3活跃线程数:3
任务3队列中的数量:1
============
============
开始执行任务:4
任务4活跃线程数:3
任务4队列中的数量:0
============
听我狡辩
1
执行结果:
============
开始执行任务:1
任务1活跃线程数:1
任务1队列中的数量:0
============
因为核心线程数为2,当执行第1个任务时核心线程数没有满,所以执行创建一个work执行当前线程
2
执行结果:
============
开始执行任务:2
任务2活跃线程数:2
任务2队列中的数量:0
============
因为核心线程数为2,当执行第2个任务时核心线程数没有满,所以执行创建一个work执行当前线程
3
执行结果:
============
开始执行任务:5
任务5活跃线程数:3
任务5队列中的数量:2
============
当执行第5个任务时,第3个、第4个任务被丢进了任务队列中,而当执行第5个的时候核心线程数满了,并且任务队列也满了(2+2-4)所以第五个任务直接创建了一个新的线程执行(maximumPoolSize)
4
执行结果:
执行了异常策略:6
因为执行第6个任务时,核心线程数满了,任务队列也满了,最大线程也满了,所以执行了丢弃策略(maximumPoolSize+queueSize=5)
5
执行结果:
============
开始执行任务:3
任务3活跃线程数:3
任务3队列中的数量:1
============
当执行第3个任务时,任务被丢到了任务队列,当有空闲的线程时,他才被执行。而执行它的时候任务队列数量从2变成1
6
执行结果:
============
开始执行任务:4
任务4活跃线程数:3
任务4队列中的数量:0
============
当执行第4个任务时,任务被丢到了任务队列,当有空闲的线程时,他才被执行。而执行它的时候任务队列数量从1变成0