理解异步的使用场景
异步会比同步更加快
例如我就拿抢票来举例子
抢票里面一般包含两个方法
抢票和下单
我们如果判断抢票成功后,那么我们可以向数据库里去下单了
但是如果我们的一个线程有两个这个方法,那我们就要等到这两个方法都执行完
但是其实我们如果判断抢到票,然后让它下单,这个线程就可以结束了,但是我们的线程要等到下单完成才结束,这样子会导致我们的接口返回有点慢
(大部分情况下是我们不需要使用异步的方法的返回值)
所以这个时候我们就要使用到异步了
说到异步,我们其实可以使用消息队列mq,kafka等,也可以使用线程池
一般如果不是分布式项目的话直接使用线程池就行了,没必要使用到mq
我们来用一个测试类来模拟一下
弄一个阻塞队列和线程池
judge方法,判断是否抢票成功
create方法,抢票成功后创建订单
我们的add方法,就是使用我们的judge方法和create方法
弄一个任务类连接Runnable接口
需要异步调用的时候把这个任务类扔进线程池就行了
我们的逻辑是,我们不断地从阻塞队列里来获取值,然后创建订单
PostConstruct初始化
我们初始化的时候就向线程池里面提交这个任务,这样子一开始就是线程池里的任务在执行了
这样子我们的这个方法当前线程只要判断是否抢票成功后,向阻塞队列添加完就结束了
有另一个异步的线程来执行下单操作
有两个不同的方法,我们来看看不同方法的使用时长是怎么样的
时间对比
异步的情况
结束时间是58秒
我们结束后订单还在创建,就说明是另一个线程在异步执行的
同步的情况
结束时间是68
一个是58,一个是68,这个速度差距非常大
ps: 我们这是执行1000次的时候的想过,亲测如果执行的次数少,例如10次,那么线程池异步的处理时间和正常代码的同步处理时间相差无几,但执行次数越多,相差越大
测试类代码
package com.example.admin;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.UUID;
import java.util.concurrent.*;
@SpringBootTest
@Slf4j
public class ThreadTest {
//阻塞队列
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(1024*1024);
//线程池
public static final ExecutorService pool= Executors.newSingleThreadExecutor();
//初始化的时候就开启线程任务
@PostConstruct
private void init(){
pool.submit(new task());
}
//这个是我们的抢票
@Test
void ticktes(){
//add里面有两个方法judge和create
add();
}
@Test
void add(){
long first = System.currentTimeMillis();
for (int i = 0; i <1000 ; i++) {
log.info("开始时间" + first);
judge(UUID.randomUUID().toString());
//这个是使用线程池
blockingQueue.add(UUID.randomUUID().toString());
//这个是不使用线程池
// create(UUID.randomUUID().toString());
}
log.info("结束时间"+(System.currentTimeMillis()-first));
}
//判断是否抢票成功
String judge(String str)
{
return "用户"+str+"抢票成功,开始下单";
}
private class task implements Runnable{
@Override
public void run() {
while(true)
{
try{
//获取订单信息
String id = blockingQueue.take();
if(id!=null)
//创建订单
create(id);
}
catch (Exception e)
{
log.error("处理异常信息",e);
}
}
}
}
//下单
private void create(String id) {
System.out.println("订单"+id+"创建成功");
log.info("创建订单"+id+"成功");
}
}