一、接口示例
1、执行体:
//sleep1 1s sleep2 5s sleep3 10s 顺序执行
public void question1() {
log.info("开始: "+simpleFormat.format(new Date()));
thirdHttpComponrent.sleep1();
thirdHttpComponrent.sleep2();
thirdHttpComponrent.sleep3();
log.info("结束: "+simpleFormat.format(new Date()));
}
2、调用方:
public void sleep1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("睡眠1秒钟: "+simpleFormat.format(new Date()));
}
public void sleep2(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("睡眠5秒钟: "+simpleFormat.format(new Date()));
}
public void sleep3(){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("睡眠10秒钟: "+simpleFormat.format(new Date()));
}
3、结论:
顺序执行,所需时间为16s,为三者之和。
二、可行性方案
1、没返回值:异步执行,前后端分离,避免请求阻塞,占用资源。
1.1、调用方加上注解@Async:
@Async
public void sleep1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("睡眠1秒钟: "+simpleFormat.format(new Date()));
}
1.2、main入口,加上@EnableAsync:
@SpringBootApplication
@EnableAsync
public class TestQuestionsApplication {
public static void main(String[] args) {
SpringApplication.run(TestQuestionsApplication.class, args);
}
}
1.3、结论:
异步执行,所需时间为10s,为三者之最;执行体执行完非异步逻辑,便立即返回
2、有返回值:后端异步执行,缓存结果(redis...),前端间断多次请求取值
2.1、执行体:
public HashMap question2(String key) {
if(!StringUtils.isEmpty(key)){
return (HashMap)hashMap.get(key);
}
key = UUID.randomUUID()+"";
HashMap result = new HashMap();
result.put("key",key);
thirdHttpComponrent.sleep4(result);
thirdHttpComponrent.sleep5(result);
thirdHttpComponrent.sleep6(result);
hashMap.put(key,result);
return (HashMap)hashMap.get(key);
}
2.2、调用方:
@Async
public void sleep4(HashMap hashMap){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
hashMap.put("sleep4","sleep4");
log.info("睡眠1秒钟: "+simpleFormat.format(new Date()));
}
@Async
public void sleep5(HashMap hashMap){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
hashMap.put("sleep5","sleep5");
log.info("睡眠5秒钟: "+simpleFormat.format(new Date()));
}
@Async
public void sleep6(HashMap hashMap){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
hashMap.put("sleep6","sleep6");
log.info("睡眠10秒钟: "+simpleFormat.format(new Date()));
}
2.3、结论:
有返回值慢接口,后端异步缓存结果,前端多次取值,避免了请求超时,长时间占用资源、阻塞线程等问题。
1,2次返回
{
"key": "d8f90881-4084-41f8-a763-f5da6aa1b327"
}
3....次返回
{
"sleep5": "sleep5",
"sleep6": "sleep6",
"sleep4": "sleep4",
"key": "d8f90881-4084-41f8-a763-f5da6aa1b327"
}
3、接口业务逻辑相互关联不大:多个线程并发执行,最后统一结果返回
3.1、执行体:
private volatile static int i = 0;
private synchronized Integer getI(){
return i++;
}
@Override
public void question3() throws InterruptedException {
// 处理队列,需要处理的数据,放置到此队列中
Queue<Integer> queue = new ConcurrentLinkedQueue<>();
// 进队 执行 线程数
CountDownLatch offerLatch = new CountDownLatch(3);
// 出队 执行 线程数
CountDownLatch pollLatch = new CountDownLatch(1);
Runnable offerRunnable = () -> {
try {
// 循环取数
while (true) {
Integer offerI = this.getI();
queue.offer(offerI);
Thread.sleep(10000);
if(offerI == 10) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 在finally中执行latch.countDown()以及信号量释放,避免因异常导致没有正常释放
offerLatch.countDown();
}
};
Runnable pollRunnable = () -> {
try {
// 只要offer的latch未执行完,或queue仍旧有数据,则继续循环
while (offerLatch.getCount() > 0 || queue.size() > 0) {
Integer poll = queue.poll();
if (poll != null) {
System.out.println(poll);
}
// 无论是否poll到数据,均暂停一小段时间,可降低CPU消耗
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 在finally中执行latch.countDown(),避免因异常导致没有正常释放
pollLatch.countDown();
}
};
// 启动一个poll线程 模拟取数据很慢,需要开启3个线程处理
new Thread(pollRunnable).start();
for (int i = 0; i < 3; i++) {
new Thread(offerRunnable).start();
}
// latch等待,直到latch的count为0
offerLatch.await();
pollLatch.await();
System.out.println("结束");
}
3.2、结论:
接口业务逻辑相互关联不大,多个线程同时并发执行,提高响应时间。