一、ThreadPoolExecutor 的参数
1 corePoolSize
:核心线程数
-
核心线程会一直存活,及时没有任务需要执行
-
当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
-
设置
allowCoreThreadTimeout
=true(默认false)时,核心线程会超时关闭
2 queueCapacity 任务队列容量(阻塞队列)
- 当核心线程数达到最大时,新任务会放在队列中排队等待执行
3 maxPoolSize 最大线程数
-
当线程数>=
corePoolSize
,且任务队列已满时。线程池会创建新线程来处理任务 -
当线程数=
maxPoolSize
,且任务队列已满时,线程池会拒绝处理任务而抛出异常
4 keepAliveTime 线程空闲时间
-
当线程空闲时间达到
keepAliveTime
时,线程会退出,直到线程数量等于corePoolSize
-
如果
allowCoreThreadTimeout
=true,则会直到线程数量=0
5 allowCoreThreadTimeout
:允许核心线程超时
6 rejectedExecutionHandler 任务拒绝处理器
6.1 两种情况会拒绝处理任务
- 当线程数已经达到
maxPoolSize
,切队列已满,会拒绝新任务 - 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
6.2 线程池会调用rejectedExecutionHandler
来处理这个任务。如果没有设置默认是AbortPolicy
,会抛出异常
6.3 ThreadPoolExecutor
类有几个内部实现类来处理这类情况:
AbortPolicy
丢弃任务,抛运行时异常CallerRunsPolicy
执行任务DiscardPolicy
忽视,什么都不会发生DiscardOldestPolicy
从队列中踢出最先进入队列(最后一个执行)的任务
6.4 实现RejectedExecutionHandler
接口,可自定义处理器
二、ThreadPoolExecutor
执行顺序
- 当线程数小于核心线程数时,创建线程。
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
- 当线程数大于等于核心线程数,且任务队列已满
- 若线程数小于最大线程数,创建线程
- 若线程数等于最大线程数,抛出异常,拒绝任务
总结:
线程各参数设置后应满足:核心线程数 < 最大线程数 < 核心线程数+队列长度 < 最大线程数+队列长度
1 顺时任务数 <= 核心线程数,线程池创建核心线程执行任务
2 顺时任务数 > 核心线程数,线程池创建所有核心线程执行任务,剩余任务放在队列中排队等待执行
3 核心线程数+队列长度 < 顺时任务数 <= 最大线程数+队列长度 时;
线程池创建线程数 = 顺时任务数 - 队列长度
如果想让线程池创建最多的线程,控制 顺时任务数 = 最大线程数+队列长度
三、例子如下:
线程池初始化类
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
return new ThreadPoolExecutor(
//核心线程数
pool.getCoreSize(),
//最大线程数
pool.getMaxSize(),
//线程空闲时间
pool.getKeepAliveTime(),
TimeUnit.SECONDS,
//队列长度
new LinkedBlockingDeque<>(pool.getLinkedBlockingDeque()),
Executors.defaultThreadFactory(),
//丢弃任务,抛运行时异常
new ThreadPoolExecutor.AbortPolicy()
);
}
}
线程池常量类
@ConfigurationProperties(prefix = "test.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize = 2;
private Integer maxSize = 6;
private Integer keepAliveTime = 60;
private Integer linkedBlockingDeque = 10;
}
测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("local")
public class MyThreadTest {
@Resource
private ThreadPoolExecutor executor;
@Resource
private ThreadPoolConfigProperties threadPoolConfigProperties;
@Test
public void test() throws InterruptedException {
List<Integer> list = new ArrayList<>();
for (int i = 1; i < 21; i++) {
list.add(i);
}
CountDownLatch test = new CountDownLatch(20);
System.out.println("开始啦:" + DateUtil.DateToString(LocalDateTime.now(), DateUtil.YYYY_MM_DD_HH_MM_SS));
for (int i = 0; i < list.size(); i ++) {
Integer item = list.get(i);
BlockingQueue<Runnable> runnables = executor.getQueue();
if(!CollectionUtils.isEmpty(runnables) &&
runnables.size() >= threadPoolConfigProperties.getLinkedBlockingDeque() &&
executor.getActiveCount() == threadPoolConfigProperties.getMaxSize()){
try {
Thread.sleep(125);
} catch (Exception e){
throw new RuntimeException(e);
}
i--;
continue;
}
Callable callable = new Callable<Long>() {
@Override
public Long call() throws Exception {
try {
testUtil(item);
} catch (Exception e) {
e.printStackTrace();
} finally {
//这个不管是否异常都需要数量减,否则会被堵塞无法结束
test.countDown();
}
return test.getCount();
}
};
System.out.println("提交前:" + item);
executor.submit(callable);
System.out.println("提交后:" + item);
}
test.await();
System.out.println("结束啦:" + DateUtil.DateToString(LocalDateTime.now(), DateUtil.YYYY_MM_DD_HH_MM_SS));
// 关闭线程池
executor.shutdown();
}
private void testUtil(int index){
try {
System.out.println("第:" + index + " 个,开始:"+ Thread.currentThread().getName());
Thread.sleep(1000);
System.out.println("第:" + index + " 个,结束:"+ Thread.currentThread().getName());
} catch (Exception e){
throw new RuntimeException(e);
}
}
}