[DONE][重要工作中的线程部分总结]springboot的线程管理(使用@Async和CountDownLatch)

 

Mayday bird nest 2019 con is coming

今日分享

啦啦啦啦啦 你想要世界

啦啦啦啦啦 就给你世界

啦啦啦啦啦 让感性撒野

啦啦啦啦啦 让理智全灭

目录

1. yml的线程配置

2. springboot中config文件的配置

3. 使用方式

4. 带计数的异步方式

5. 更多关于CountDownLatch(倒计时器)

6.接口的 RT是什么?


1. yml的线程配置

thread:
  core-pool-size: 10            # 核心线程数(默认线程数)
  max-pool-size: 100            # 最大线程数
  keep-alive-time: 10           # 允许线程空闲时间(单位:默认为秒)
  queue-capacity: 200           # 缓冲队列数
  name-prefix: Async-Service-   # 线程池名前缀

2. springboot中config文件的配置

package com.situdata.situciticpru.common.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Description : 
 * @Date : 2019/8/8
 * @Author : 
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
/*
    如下方式会使@Async失效
    一、异步方法使用static修饰
    二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
    三、异步方法不能与异步方法在同一个类中
    四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
    五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
    六、在本类中调用本累得异步方法无效
    */

    @Value("${thread.core-pool-size}")
    private int corePoolSize;            // 核心线程数(默认线程数)
    @Value("${thread.max-pool-size}")
    private int maxPoolSize;                // 最大线程数
    @Value("${thread.keep-alive-time}")
    private int keepAliveTime;            // 允许线程空闲时间(单位:默认为秒)
    @Value("${thread.queue-capacity}")
    private int queueCapacity;            // 缓冲队列数
    @Value("${thread.name-prefix}")
    private String threadNamePrefix;        // 线程池名前缀

    @Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveTime);
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 线程池对拒绝任务的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }
}

其实最主要的是

@EnableAsync  与 让spring注入ThreadPoolTaskExecutor

其实也就是创建了一个ThreadPoolTaskExecutor然后来通过配置里面读取参数设置,然后进行设置

3. 使用方式

在service中加入@Async注解就可以实现;

@Component
public class SyncServiceImpl implements SyncService {

    @Override
    @Async
    public void uploadAudioAndAsr() {
       
    }

}

serviece要加上@Compent注解,然后想异步的方法就可以加上@Async注解来实现!!

@Component注解(或其他注解)是为了让spring扫描的到!

4. 带计数的异步方式

CountDownLatch countDownLatch = new CountDownLatch(list.size());
                for (Map<String, String> map : list) {
                    orderSyncService.ttsAndPutStream(basePath, map.get("name"), map.get("text"),countDownLatch);
                }
                countDownLatch.await();

这是一个TTS文字转语音的方法;

因为文字有很多段,需要全部生成完毕才能打包给前端;

所以 使用一个计数器的方法,让每次执行完一个,就把这个countDownLatch进行减一

所以这种方式可以让所有的子线程进行等待;

是一种比较好的方式来实现业务需求;

在tts的业务类里面是这样实现这个方法的;

  @Async
    @Override
    public void ttsAndPutStream(String basePath, String name, String text, CountDownLatch countDownLatch) throws IOException {
        speechService.speechSynthesizer(text, basePath + name + ".mp3");
        countDownLatch.countDown();
    }

5. 更多关于CountDownLatch(倒计时器)

早在java 1.5就有这个倒计时器了;

常用的方法:

CountDownLatch(int count) //实例化一个倒计数器,count指定计数个数
countDown() // 计数减一
await() //等待,当计数减到0时,所有线程并行执行

更多使用场景:

比如一个API接口响应时间要求在200ms内,但是里面依赖了多个第三方的api或者外部服务

那么如果不使用异步就会调用很久,所以使用最多的是接口RT优化场景,内部服务并行调用。

其实使用方式都是那三个常用方法;也很简单

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Description : CountDownTest
 * @Date : 2019/8/21
 * @Author : 
 */
public class CountDownTest implements Runnable {


    static final CountDownLatch latch = new CountDownLatch(10);
    static final CountDownTest demo = new CountDownTest();

    @Override
    public void run() {
        // 模拟检查任务
        try {
            Thread.sleep(new Random().nextInt(10) * 1000);
            System.out.println("check complete");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //计数减一
            //放在finally避免任务执行过程出现异常,导致countDown()不能被执行
            latch.countDown();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            exec.submit(demo);
        }

        // 等待检查
        latch.await();

        // 发射火箭
        System.out.println("Fire!");
        // 关闭线程池
        exec.shutdown();
    }

}

代码转自:https://www.jianshu.com/p/f17692e9114f

6.接口的 RT是什么?

Reaction Time(响应时间)    riˈækʃn

1. 项目级的处理方案:有些公共的功能,并不需要每个开发去写代码,比如异常处理,直接往上抛,会有统一的代码捕捉异常进行处理的。(业务代码可以直接throw一个封装的异常)

public class ResultException extends RuntimeException {
    public ResultException(RespCode respCode, String result) {
        super(FastJsonUtils.toJsonString(new Result(respCode, result)));
    }

    public ResultException(RespCode respCode) {
        super(FastJsonUtils.toJsonString(new Result(respCode, null)));
    }

    public ResultException(int code, String msg, String result) {
        super(FastJsonUtils.toJsonString(new Result(code, msg, result)));
    }

    public ResultException(int code, String msg) {
        super(FastJsonUtils.toJsonString(new Result(code, msg, null)));
    }
}

封装的统一异常其实就是继承runtime异常类;

然后可以往上抛;

这个是Runtime的源码;

 public RuntimeException(String message) {
        super(message);
    }

然后用统一的异常类 进行捕获;

2.接口的拆分

避免万能接口,就是根据不同的入参来进行不同的业务逻辑(yitu。。。)

但是还是要看业务的需要;

垂直拆分:把一个大接口哦拆分成独立的小接口

水平拆分:部署多个接口,复杂均衡;

另外一种就是5.中提到的并行处理内部接口调用;

3. 缓存

1.少创建对象可以减少RT 可以启动的时候就放入内存

2.能查询缓存就尽量不要用查询数据库的方式;

3.MQ 用于 通知 ? ?  

4. 有些出入参可以直接用用MD5保存到redis中;  这种就是有时候入参不变 客户多掉两次;

此部分参考:https://blog.csdn.net/zhangbijun1230/article/details/90900415

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值