名词解释
1)同步:等用户所有操作结束后,才会返回程序的处理状态。
2)异步:直接返回给用户指定的状态,同时程序在后台继续运行,用户不用等待。
实现
同步实现
@Autowired
private TaskAsync taskAsync;
/**
* 同步处理的方式
*/
@GetMapping("/test2")
public String test2() {
taskAsync.getTest2();
System.out.println(Thread.currentThread().getName() + "==========主线程名");
return "同步,正在解析......";
}
@Component
public class TaskAsync {
public void getTest2() {
Building building = new Building();
synchronized (building) {
try {
for (int i = 0; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "----------同步:>" + i);
building.wait(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这种同步的方式处理,会发现,当这100此循环完成后,页面才会返回 :同步,正在解析......。当后台在循环处理时,前台的页面始终处于等待状态。可以发现,使用都是一个线程在处理:
异步实现方式一
使用线程池,创建新的线程去处理,如下:
/**
* 异步处理方式一:线程池,创建新线程处理
*/
@GetMapping("/test3")
public String test3() {
ExecutorService service = Executors.newFixedThreadPool(5);
RunnableTask1 task1 = new RunnableTask1();
service.execute(task1);
System.out.println("=========》当前线程名:" + Thread.currentThread().getName());
return "异步,正在解析......";
}」
public class RunnableTask1 implements Runnable {
@Override
public void run() {
Building building = new Building();
synchronized (building) {
try {
for (int i = 0; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "----------异步:>" + i);
building.wait(200);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
我们看控制台,会发现,主线程和处理任务的线程,不是一个线程,也就是,当页面请求后,主线程会返回我们想要返回的标识,这里返回的是一个字符串:异步,正在解析......,而线程池新开了一个线程,在后台处理业务逻辑。所以,此时访问接口后,会立马返回,页面不用等待,处理逻辑在后台默默进行。控制台如下:
异步实现方式二
这种方式,是SpringBoot自身的一种异步方式,使用注解实现,非常方便。
SpringBoot要使用@Async需要以下两个步骤:
1.使用@EnableAsync开启异步;(在项目的启动类上)
2.定义Spring组件,使用@Component和@Async;
注意,这里的异步方法,只能在自身之外调用,在本类调用是无效的。
/**
* 异步方法
* 有@Async注解的方法,默认就是异步执行的,会在默认的线程池中执行,但是此方法不能在本类调用;启动类需添加直接开启异步执行@EnableAsync。
*/
@GetMapping("/test1")
public String test1() {
taskAsync.getTest1();
System.out.println(Thread.currentThread().getName() + "=========================");
return "异步,正在解析......";
}
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class TaskAsync {
@Async
public String getTest1() {
Building building = new Building();
synchronized (building) {
try {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "----------异步:>" + i);
building.wait(200);
}
return "执行异步任务完毕";
} catch (Exception ex) {
ex.printStackTrace();
}
}
return Thread.currentThread().getName() + "执行完毕";
}
}
看控制台,会发现,页面发出请求后,主线程会返回,而内置的线程池会新开线程,在后台执行任务。此时页面不用等待,可以继续其他操作。
可以看到,很多情况下,异步处理,是一种很常见,而且很高效的方式,个人比较喜欢使用springBoot自带的注解方式,只用两个注解即可了。