java中线程池之ThreadPoolExecutor简单分析

一、ThreadPoolExecutor 的参数

1 corePoolSize:核心线程数
  • 核心线程会一直存活,及时没有任务需要执行

  • 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理

  • 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭

2 queueCapacity 任务队列容量(阻塞队列)
  • 当核心线程数达到最大时,新任务会放在队列中排队等待执行
3 maxPoolSize 最大线程数
  • 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务

  • 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常

4 keepAliveTime 线程空闲时间
  • 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量等于corePoolSize

  • 如果allowCoreThreadTimeout=true,则会直到线程数量=0

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. 当线程数大于等于核心线程数,且任务队列已满
    1. 若线程数小于最大线程数,创建线程
    2. 若线程数等于最大线程数,抛出异常,拒绝任务

总结:

线程各参数设置后应满足:核心线程数 < 最大线程数  < 核心线程数+队列长度 < 最大线程数+队列长度

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);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值