1. 使用CompletableFuture
实例如下:
@Autowired
@Resource(name = "threadPoolTaskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@GetMapping
public String testAsync() {
CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步方法执行成功2, 线程名: " + Thread.currentThread().getName());
return "异步方法执行成功";
// 这里可传入值自定义的线程池, 否则是默认
}, threadPoolTaskExecutor);
return "success";
}
2. 通过 @Async 注解
参数是 线程池对象名
这里直接在同一个类中是不行了, 错误方式如下:
// 这样还是一个同步方法
@GetMapping
public String testAsync() {
test();
return "success";
}
@Async("threadPoolTaskExecutor")
public void test() {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步方法执行成功");
}
// 这段代码中虽然使用了@Async注解来标记test方法,
// 但在testAsync方法中直接调用了test方法,而没有通过异步的方式调用。
// 在Spring框架中,@Async注解只能在其他bean方法内部被调用,
// 因为它通过创建一个代理对象来实现异步调用
正确方式1
-
定义一个共同的bean用来处理异步方法
@Data @Component public class CommonAsyncComponent { @Async("threadPoolTaskExecutor") public void test() { try { Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("异步方法执行成功"); } }
主方法中调用
@Autowired private CommonAsyncComponent commonAsyncComponent; @GetMapping public String testAsync(){ commonAsyncComponent.test(); return "success"; }
正确方式2
在server的实现类中直接使用**@Async**注解, 这样在控制层调用时就直接是异步方法
@Override
@Async("threadPoolTaskExecutor")
public void test() {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("service异步方法执行成功");
}
3. 使用Thread
这里是创建一个新的线程来执行, 而不是从线程池中直接获取, 但是存在一些问题
- 可维护性:直接创建线程可能导致代码可读性和可维护性降低,尤其是在复杂的应用中。
- 控制性差:线程的生命周期和资源管理需要手动处理,容易导致资源泄漏或线程安全问题。
- 可扩展性差:对于大规模应用,手动管理线程可能不是最优选择,因为它难以扩展和优化。
new Thread(() -> {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("controller异步方法执行成功");
}).start();