ThreadPoolExecutor 是 java.util.concurrent 包下的类
一、创建线程池
public class ThreadPoolConfig {
private static volatile ThreadPoolExecutor threadPoolExecutor = null;
private ThreadPoolConfig() {
}
/* int corePoolSize: 核心线程数
* int maximumPoolSize: 最大线程数,及当前线程允许创建多少个线程
* long keepAliveTime && TimeUnit unit: 表示线程池没任务,线程存活多久销毁
* BlockingQueue<Runnable> workQueue: 任务队列大小,如果不设置默认大小为Integer.MAX_VALUE
* ThreadFactory threadFactory: 线程工厂,创建线程时用,一般用来给线程设置参数,比如线程名
* RejectedExecutionHandler handler: 拒绝策略,如果线程池满了,新来的线程怎么处理,默认策略 java.util.concurrent.AbortPolicy
*/
public static synchronized ThreadPoolExecutor getInstance() {
if (null == threadPoolExecutor) {
threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(60), new MyThreadFactory(), new MyRejectedExecutionHandler());
}
return threadPoolExecutor;
}
}
二、线程工厂
public class MyThreadFactory implements ThreadFactory {
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
@Override
public Thread newThread(Runnable r) {
// \uD83D\uDE42 : 🙂
// 自定义线程名
return new Thread(r, "thread-\uD83D\uDE42-" + nextThreadNum());
}
三、自定义拒绝策略
public class MyRejectedExecutionHandler implements RejectedExecutionHandler {
private static int taskNumber;
private static synchronized void nextThreadNum() {
taskNumber++;
}
/* RejectedExecutionHandler 拒绝策略提供了如下四种
* java.util.concurrent.AbortPolicy 抛出异常
* java.util.concurrent.CallerRunsPolicy 交给主线程执行
* java.util.concurrent.DiscardPolicy 丢弃不做任何处理
* java.util.concurrent.DiscardOldestPolicy 移除队列第一个任务,添加当前任务
*/
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
nextThreadNum();
// 在队列满时,可以自定义最大线程数
/* if (!executor.isShutdown()) {
if (executor.getMaximumPoolSize() < executor.getQueue().size() / 2) {
executor.setMaximumPoolSize(executor.getMaximumPoolSize() + 1);
}
}*/
// 拒绝策略抛出异常
//throw new RejectedExecutionException("Task " + r.toString() +" rejected from " + executor.toString());
// 模拟拒绝策略抛出异常
System.out.println("执行" + taskNumber + "拒绝策略,抛出异常");
}
}
四、测试
比如一次性提交了 100 个任务,按照下面的线程池参数,100 个任务是如何执行的
- 1、首先线程池会创建 5 个线程去执行前 5 个任务
- 2、从第六个任务开始都会放到任务队列中,即 LinkedBlockingQueue 中
- 3、当任务队列中 60 个任务放满后,这时候未处理还剩 35 个任务,已处理 65 个(任务队列 60 个 + 在执行 5 个)
- 4、第 65 ~ 70 个任务会直接创建执行,只能创建 5 个(最大线程数 10 - 核心线程数 5 )
- 5、第 71 ~ 100 个任务,因为线程池满了,最大线程数 10 也满了,会进入指定的拒绝策略
public class ThreadPoolTest {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
ThreadPoolExecutor threadPoolExecutor = ThreadPoolConfig.getInstance();
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(() -> {
System.out.println("线程名:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
/* 统计多线程运行时长 */
// 等待线程池中正在执行和待执行线程执行完成,再关闭线程池
threadPoolExecutor.shutdown();
// 立马关闭线程,不管线程池中是否有正在执行或待执行线程
//threadPoolExecutor.shutdownNow();
System.out.println(threadPoolExecutor.getQueue().size());
boolean flag= true;
while (flag) {
// isShutDown 方法:当调用 shutdown() 或 shutdownNow() 方法后返回为 true。
// isTerminated 方法: 当调用 shutdown() 并且所有提交的任务完成后返回为 true;
// isTerminated 方法: 当调用 shutdownNow() 成功停止后返回为 true;
if(threadPoolExecutor.isTerminated()){
flag = false;
long endTime = System.currentTimeMillis();
System.out.println("------线程池运行时长-------"+(endTime - startTime));
}
}
}
}
根据上面线程池配置以及 Thread.sleep(1000),则每个任务睡眠 1000 ms,最大线程数加上队列大小总共 70 个任务,1000 ms可执行最大线程数 10 个任务,线程池运行时长最少 7000 ms,结果如下,可以看到多线程运行时长 7169 ms