学习笔记day02(线程池ThreadPoolTaskExecutor+流处理之flatMap)

一、ThreadPoolTaskExecutor

	@Autowired
	@Qualifier(value = "contractProcessExector")
	private ThreadPoolTaskExecutor contractProcessExector;



@Configuration
public class ExecutorConfig {
	@Bean("contractProcessExector")
	public ThreadPoolTaskExecutor contractProcessExector() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		int i = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
		executor.setCorePoolSize(1);//核心池大小
		executor.setMaxPoolSize(10);//最大线程数
		executor.setQueueCapacity(500);//队列程度
		executor.setKeepAliveSeconds(300);//线程空闲时间
		executor.setThreadNamePrefix("tsak-asyn");//线程前缀名称
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置拒绝策略
		return executor;
	}
}

@Qualifier的作用:把某个对象作为属性赋值给另一个对象

CountDownLatch countDownLatch = new CountDownLatch(integrationContractDOS.size());

		integrationContractDOS.forEach(contractDO -> {
			try {
				ContractProcessCheck contractProcessCheck = contractProcessCheckFactory.getImpl(contractDO);
				if(null == contractProcessCheck){
					countDownLatch.countDown();
					return;
				}
                ....
				contractProcessExector.execute(new ContractProcessThread(contractProcess, contractDO, countDownLatch));
			} catch (Exception e) {
               ....
				countDownLatch.countDown();
			}
		});
		
		countDownLatch.await();

CountDownLatch的两种用法,此处使用的是第一种

1、某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行

2、实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计算器初始化为1,多个线程在开始执行任务前首先countdownlatch.await(),当主线程调用countDown()时,计数器变为0,多个线程同时被唤醒

@Slf4j
public class ContractProcessThread implements Runnable {

	private ContractProcess contractProcess;

	private IntegrationContractDO contractDO;

	private CountDownLatch countDownLatch;

	public ContractProcessThread (ContractProcess contractProcess, IntegrationContractDO contractDO, CountDownLatch countDownLatch){
		this.contractProcess = contractProcess;
		this.contractDO = contractDO;
		this.countDownLatch = countDownLatch;
	}

	@Override
	public void run() {
		try {
			TraceLogUtil.setTraceLogId();
			contractProcess.doContractProcess(contractDO);
		} catch (Exception e) {
            ...
		} finally {
			countDownLatch.countDown();
		}
	}
}

二、ThreadPoolExecutor

	private static final ExecutorService THREAD_POOL = new ThreadPoolExecutor(10, 20, 20,
			TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("oppo-authApply-pool-%d").build());
			orderDetailMap.entrySet().forEach(entry -> {
				futureList.add(THREAD_POOL.submit(() -> {
                    ...
				}));
			});

ThreadPoolTaskExecutor和ThreadPoolExecutor区别

ThreadPoolExecutor是一个java类不提供spring生命周期和参数装配。

ThreadPoolTaskExecutor实现了InitializingBean, DisposableBean ,xxaware等,具有spring特性

1、ThreadPoolTaskExecutor使用ThreadPoolExecutor并增强,扩展了更多特性
2、ThreadPoolTaskExecutor只关注自己增强的部分,任务执行还是ThreadPoolExecutor处理。
3、前者spring自己用着爽,后者离开spring我们用ThreadPoolExecutor爽。
注意:ThreadPoolTaskExecutor 不会自动创建ThreadPoolExecutor需要手动调initialize才会创建
    如果@Bean 就不需手动,会自动InitializingBean的afterPropertiesSet来调initialize

ThreadPoolExecutor核心参数说明

    1、corePoolSize:核心线程数
        * 核心线程会一直存活,及时没有任务需要执行
        * 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
        * 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
 
    2、queueCapacity:任务队列容量(阻塞队列)
        * 当核心线程数达到最大时,新任务会放在队列中排队等待执行
 
    3、maxPoolSize:最大线程数
        * 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
        * 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
 
    4、 keepAliveTime:线程空闲时间
        * 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
        * 如果allowCoreThreadTimeout=true,则会直到线程数量=0
 
    5、allowCoreThreadTimeout:允许核心线程超时
    6、rejectedExecutionHandler:任务拒绝处理器
        * 两种情况会拒绝处理任务:
            - 当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
            - 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
        * 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常
        * ThreadPoolExecutor类有几个内部实现类来处理这类情况:
            - AbortPolicy 丢弃任务,抛运行时异常
            - CallerRunsPolicy 执行任务
            - DiscardPolicy 忽视,什么都不会发生
            - DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
        * 实现RejectedExecutionHandler接口,可自定义处理器

三、流处理之flatMap

此时有一个需求,需要判断一个嵌套list中是否包含某个元素等于指定的值,此时如果是用两层for循环则会显得代码很冗余,此时可以用到flatMap将流进行扁平化处理,将两层list转换成一个list再进行判断

代码示例:

Boolean flag = refundDetailList.stream().filter(
                refundDetail -> refundDetail.getRepaymentPlanList().stream().filter(repaymentPlan -> "ccc".equals(repaymentPlan.getRefundType())).findAny().isPresent()
                ).findAny().isPresent();
        for(ResDto.RefundDetail refundDetail:refundDetailList){
            for(ResDto.RefundDetail.RepaymentPlan repaymentPlan:refundDetail.getRepaymentPlanList()){
                if("ccc".equals(repaymentPlan.getRefundType())){
                    flag = true;
                    break;
                }
            }
        boolean b = refundDetailList.stream().flatMap(e -> e.getRepaymentPlanList().stream()).anyMatch(e -> "ccc".equals(e.getRefundType()));

这三种处理结果是一样的,但是显然第三种代码比较简单一点

四、springboot自动装配原理

在springboot的启动类中有个组合注解 @SpringbootApplication 此注解中有@EnableAutoConfiguration注解用于开启自动配置,对Jar包下的spring.factorites文件进行扫描,此文件中包含了可以进行自动配置的类,当满足@Conditition注解指定的条件时,便在依赖的支持下进行实例化 注册到spring容器中

在@EnableAutoConfiguration注解中有个@Import注解,此注解导入了AutoConfigurationImportSelector类,该类有一个重要方法,selectImports 几乎涵盖了组件装配的所有处理逻辑、包括获得候选配置类、配置类去重、排除不需要的配置类 过滤等 最终返回符合条件的自动配置类的全限定名数组

如何得到候选的配置类,可以看到所有的配置信息通过getCandidateConfigurations得到,并最终由一个列表保存

getCandidateConfigurations()方法通过SpringFactoriesLoader加载器加载META-INF/spring.factories文件,首先通过这个文件获取到每个配置类的url,再通过这些url将它们封装成Properties对象,最后解析内容存于Map<String,List<String>>中

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值