CompletableFuture 是 Java 8 新增的一个异步编程工具,它可以方便地实现异步任务。使用 CompletableFuture 需要满足以下条件:
异步任务的返回值类型必须是 CompletableFuture 类型;
在异步任务中使用 CompletableFuture.supplyAsync() 或 CompletableFuture.runAsync() 方法来创建异步任务;
在主线程中使用 CompletableFuture.get() 方法获取异步任务的返回结果。
我们创建一个服务类,里面包含了异步方法和普通方法。
import org.springframework.stereotype.Service; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; /** * @author qinxun * @date 2023-06-07 * @Descripion: 异步服务类 */ @Service public class AsyncService { /** * 普通任务操作1 */ public String task1() throws InterruptedException { TimeUnit.SECONDS.sleep(3); return "任务执行完成1"; } /** * 普通任务操作2 */ public String task2() throws InterruptedException { TimeUnit.SECONDS.sleep(2); return "任务执行完成2"; } /** * 普通任务操作3 */ public String task3() throws InterruptedException { TimeUnit.SECONDS.sleep(3); return "任务执行完成3"; } /** * 异步操作1 */ public CompletableFutureasyncTask1() { return CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } return "异步任务执行完成1"; }); } /** * 异步操作2 */ public CompletableFuture asyncTask2() { return CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } return "异步任务执行完成2"; }); } /** * 异步操作3 */ public CompletableFuture asyncTask3() { return CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } return "异步任务执行完成3"; }); } }
我们先测试普通方法的情况,看看最后耗时
import cn.hutool.core.date.StopWatch; import com.example.quartzdemo.service.AsyncService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @author qinxun * @date 2023-06-07 * @Descripion: 异步处理测试 */ @SpringBootTest public class AsyncTest { @Autowired private AsyncService asyncService; @Test void test1() throws InterruptedException { StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 异步操作 /* CompletableFuturecompletableFuture1 = asyncService.asyncTask1(); CompletableFuture completableFuture2 = asyncService.asyncTask2(); CompletableFuture completableFuture3 = asyncService.asyncTask3(); System.out.println(completableFuture1.get()); System.out.println(completableFuture2.get()); System.out.println(completableFuture3.get());*/ // 同步操作 System.out.println(asyncService.task1()); System.out.println(asyncService.task2()); System.out.println(asyncService.task3()); stopWatch.stop(); System.out.println("耗时:" + stopWatch.getTotalTimeMillis()); } }
程序执行的结果:
任务执行完成1 任务执行完成2 任务执行完成3 耗时:8008
我们可以发现,普通同步方法是按顺序一个个操作的,各个方法不会同时处理。下面我们把这些操作换成异步的方法测试。
import cn.hutool.core.date.StopWatch; import com.example.quartzdemo.service.AsyncService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; /** * @author qinxun * @date 2023-06-07 * @Descripion: 异步处理测试 */ @SpringBootTest public class AsyncTest { @Autowired private AsyncService asyncService; @Test void test1() throws InterruptedException, ExecutionException { StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 异步操作 CompletableFuturecompletableFuture1 = asyncService.asyncTask1(); CompletableFuture completableFuture2 = asyncService.asyncTask2(); CompletableFuture completableFuture3 = asyncService.asyncTask3(); System.out.println(completableFuture1.get()); System.out.println(completableFuture2.get()); System.out.println(completableFuture3.get()); // 同步操作 /*System.out.println(asyncService.task1()); System.out.println(asyncService.task2()); System.out.println(asyncService.task3());*/ stopWatch.stop(); System.out.println("耗时:" + stopWatch.getTotalTimeMillis()); } }
程序执行结果:
异步任务执行完成1 异步任务执行完成2 异步任务执行完成3 耗时:3008
发现几个方法是异步同时进行的,没有先后的顺序,大大提高了程序执行效率。
@Async 注解是 Spring 提供的一种轻量级异步方法实现方式,它可以标记在方法上,用来告诉 Spring 这个方法是一个异步方法,Spring 会将这个方法的执行放在异步线程中进行。使用 @Async 注解需要满足以下条件:
需要在 Spring Boot 主类上添加 @EnableAsync 注解启用异步功能;
需要在异步方法上添加 @Async 注解。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication // 主类上加上这个注解,开启异步功能 @EnableAsync public class QuartzDemoApplication { public static void main(String[] args) { SpringApplication.run(QuartzDemoApplication.class, args); } }
修改测试的服务层
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * @author qinxun * @date 2023-06-07 * @Descripion: 异步服务类 */ @Service public class AsyncService { /** * 同步任务操作1 */ public String task1() throws InterruptedException { TimeUnit.SECONDS.sleep(3); return "任务执行完成1"; } /** * 同步任务操作2 */ public String task2() throws InterruptedException { TimeUnit.SECONDS.sleep(2); return "任务执行完成2"; } /** * 同步任务操作3 */ public String task3() throws InterruptedException { TimeUnit.SECONDS.sleep(3); return "任务执行完成3"; } /** * 异步操作1 */ @Async public FutureasyncTask1() throws InterruptedException { long currentTimeMillis = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(3); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task1任务耗时:" + (currentTimeMillis1 - currentTimeMillis) + "ms"); return new AsyncResult<>("task1完成"); } /** * 异步操作2 */ @Async public Future asyncTask2() throws InterruptedException { long currentTimeMillis = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(2); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task1任务耗时:" + (currentTimeMillis1 - currentTimeMillis) + "ms"); return new AsyncResult<>("task2完成"); } /** * 异步操作3 */ @Async public Future asyncTask3() throws InterruptedException { long currentTimeMillis = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(3); long currentTimeMillis1 = System.currentTimeMillis(); System.out.println("task1任务耗时:" + (currentTimeMillis1 - currentTimeMillis) + "ms"); return new AsyncResult<>("task3完成"); } }
创建一个测试类
import com.example.quartzdemo.service.AsyncService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; /** * @author qinxun * @date 2023-06-07 * @Descripion: */ @RestController public class AsyncController { @Autowired private AsyncService asyncService; /** * 测试异步 */ @RequestMapping("/async") public String testAsync() throws InterruptedException, ExecutionException { long currentTimeMillis = System.currentTimeMillis(); Futuretask1 = asyncService.asyncTask1(); Future task2 = asyncService.asyncTask2(); Future task3 = asyncService.asyncTask3(); while (true) { if (task1.isDone() && task2.isDone() && task3.isDone()) { // 三个任务都调用完成,退出循环等待 break; } } System.out.println(task1.get()); System.out.println(task2.get()); System.out.println(task3.get()); long currentTimeMillis1 = System.currentTimeMillis(); return "task任务总耗时:" + (currentTimeMillis1 - currentTimeMillis) + "ms"; } }
执行测试方法
task1任务耗时:2006ms task1任务耗时:3011ms task1任务耗时:3011ms task1完成 task2完成 task3完成
TaskExecutor 是 Spring 提供的一个接口,它定义了一个方法 execute(),用来执行异步任务。使用 TaskExecutor 需要满足以下条件:
需要在 Spring 配置文件中配置一个 TaskExecutor 实例;
在异步方法中调用 TaskExecutor 实例的 execute() 方法来执行异步任务。
创建一个异步配置类
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; /** * @author qinxun * @date 2023-06-07 * @Descripion: 异步处理配置类 */ @Configuration public class AsyncConfig implements AsyncConfigurer { @Bean(name = "asyncExecutor") public TaskExecutor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(100); executor.setThreadNamePrefix("async-"); executor.initialize(); return executor; } @Override public Executor getAsyncExecutor() { return asyncExecutor(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new SimpleAsyncUncaughtExceptionHandler(); } }
修改下服务类,我们使用自定义的异步配置
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * @author qinxun * @date 2023-06-07 * @Descripion: 异步服务类 */ @Service public class AsyncService { @Autowired @Qualifier("asyncExecutor") private TaskExecutor taskExecutor; /** * 同步任务操作1 */ public String task1() throws InterruptedException { TimeUnit.SECONDS.sleep(3); return "任务执行完成1"; } /** * 同步任务操作2 */ public String task2() throws InterruptedException { TimeUnit.SECONDS.sleep(2); return "任务执行完成2"; } /** * 同步任务操作3 */ public String task3() throws InterruptedException { TimeUnit.SECONDS.sleep(3); return "任务执行完成3"; } /** * 异步操作1 */ @Async public void asyncTask1() { taskExecutor.execute(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } }); System.out.println("异步任务执行完成1"); } /** * 异步操作2 */ @Async public void asyncTask2() throws InterruptedException { taskExecutor.execute(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } }); System.out.println("异步任务执行完成2"); } /** * 异步操作3 */ @Async public void asyncTask3() throws InterruptedException { taskExecutor.execute(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } }); System.out.println("异步任务执行完成3"); } }
测试类进行测试
/** * @author qinxun * @date 2023-06-07 * @Descripion: 异步处理测试 */ @SpringBootTest public class AsyncTest { @Autowired @Qualifier("asyncExecutor") private TaskExecutor taskExecutor; @Test void test1() { StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 异步操作 /* asyncService.asyncTask1(); asyncService.asyncTask2(); asyncService.asyncTask3();*/ taskExecutor.execute(() -> System.out.println("异步任务")); // 同步操作 /*System.out.println(asyncService.task1()); System.out.println(asyncService.task2()); System.out.println(asyncService.task3());*/ stopWatch.stop(); System.out.println("耗时:" + stopWatch.getTotalTimeMillis()); } }
耗时:6 异步任务执行完成3 异步任务执行完成1 异步任务执行完成2
上一篇:SQL Server基础之游标