Mayday bird nest 2019 con is coming
今日分享
啦啦啦啦啦 你想要世界
啦啦啦啦啦 就给你世界
啦啦啦啦啦 让感性撒野
啦啦啦啦啦 让理智全灭
目录
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