비동기 호출을 활성화하려면 @EnableAsync 주석을 SpringBoot 애플리케이션에 추가해야 합니다. 일반적으로 스레드 풀이 구성되고 비동기 메서드는 다음과 같이 완료를 위해 특정 스레드 풀로 전달됩니다.
@Configuration @EnableAsync public class AsyncConfiguration { @Bean("doSomethingExecutor") public Executor doSomethingExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程数:线程池创建时候初始化的线程数 executor.setCorePoolSize(10); // 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程 executor.setMaxPoolSize(20); // 缓冲队列:用来缓冲执行任务的队列 executor.setQueueCapacity(500); // 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁 executor.setKeepAliveSeconds(60); // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池 executor.setThreadNamePrefix("do-something-"); // 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程) executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.initialize(); return executor; } }
사용방법은 매우 간단합니다. 비동기 방식이 필요한 메소드에는 @Async 주석을 추가합니다.
@RestController public class AsyncController { @Autowired private AsyncService asyncService; @GetMapping("/open/something") public String something() { int count = 10; for (int i = 0; i < count; i++) { asyncService.doSomething("index = " + i); } return "success"; } } @Slf4j @Service public class AsyncService { // 指定使用beanname为doSomethingExecutor的线程池 @Async("doSomethingExecutor") public String doSomething(String message) { log.info("do something, message={}", message); try { Thread.sleep(1000); } catch (InterruptedException e) { log.error("do something error: ", e); } return message; } }
액세스: 127.0.0.1:8080/open/something, 로그는 다음과 같습니다
2023-02-06 23:42 :42.486 INFO 21168 --- [io-8200-exec -17] x.g.b.system.controller.AsyncController : 작업 종료, 시간 8밀리초
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something -1] x.gits.boot.system.service.AsyncService : 뭔가를 하세요, message=index = 0
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-5] x.gits. boot.system.service.AsyncService : 뭔가를 하세요, 메시지= 인덱스 = 4
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-4] x.gits.boot.system.service.AsyncService : 뭔가를 하세요, message=index = 3
2023-02 -06 23:42:42.488 INFO 21168 --- [ do-something-6] x.gits.boot.system.service.AsyncService : 뭔가를 하세요, message=index = 5
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-9] x.gits.boot.system.service.AsyncService : 뭔가를 하세요, message=index = 8
2023-02- 06 23:42:42.488 INFO 21168 --- [ do -something-8] x.gits.boot.system.service.AsyncService : 뭔가를 하세요, message=index = 7
2023-02-06 23:42:42.488 INFO 21168 --- [do-something-10] x.gits.boot.system.service.AsyncService : 뭔가를 하세요, message=index = 9
2023-02-06 23:42:42.488 INFO 21168 --- [ do- Something-7] x.gits.boot.system.service .AsyncService : do what, message=index = 6
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-2] x.gits .boot.system.service.AsyncService : 뭔가를 하세요, 메시지 =index = 1
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-3] x.gits.boot.system.service. AsyncService : do Something, message=index = 2
비동기 실행 효과가 나타나고, 우리가 구성한 스레드 풀이 사용된 것을 볼 수 있습니다.
비동기 메서드에 반환 값이 있는 경우 비동기 메서드 실행의 반환 결과를 어떻게 가져오나요? 이때 비동기적으로 호출되어야 하는 메소드는 반환값이 CompletableFuture입니다.
CompletableFuture는 기능이 향상된 기능으로 간단한 비동기 작업만 처리할 수 있는 반면 CompletableFuture는 여러 비동기 작업의 복잡한 조합을 수행할 수 있습니다. 다음과 같습니다:
@RestController public class AsyncController { @Autowired private AsyncService asyncService; @SneakyThrows @ApiOperation("异步 有返回值") @GetMapping("/open/somethings") public String somethings() { CompletableFuture<String> createOrder = asyncService.doSomething1("create order"); CompletableFuture<String> reduceAccount = asyncService.doSomething2("reduce account"); CompletableFuture<String> saveLog = asyncService.doSomething3("save log"); // 等待所有任务都执行完 CompletableFuture.allOf(createOrder, reduceAccount, saveLog).join(); // 获取每个任务的返回结果 String result = createOrder.get() + reduceAccount.get() + saveLog.get(); return result; } } @Slf4j @Service public class AsyncService { @Async("doSomethingExecutor") public CompletableFuture<String> doSomething1(String message) throws InterruptedException { log.info("do something1: {}", message); Thread.sleep(1000); return CompletableFuture.completedFuture("do something1: " + message); } @Async("doSomethingExecutor") public CompletableFuture<String> doSomething2(String message) throws InterruptedException { log.info("do something2: {}", message); Thread.sleep(1000); return CompletableFuture.completedFuture("; do something2: " + message); } @Async("doSomethingExecutor") public CompletableFuture<String> doSomething3(String message) throws InterruptedException { log.info("do something3: {}", message); Thread.sleep(1000); return CompletableFuture.completedFuture("; do something3: " + message); } }
액세스 인터페이스
C:UsersAdministrator>curl -X GET "http://localhost:8080/open/something" -H "accept: */*"
do Something1: 주문 생성;
do Something2 : 계정 축소;
do Something3: 로그 저장
콘솔의 주요 로그는 다음과 같습니다.
2023-02-06 00:27:42.238 INFO 5672 --- [ do-something-3] x .gits.boot .system.service.AsyncService : do Something3: 로그 저장
2023-02-06 00:27:42.238 INFO 5672 --- [ do-something-2] x.gits.boot.system.service.AsyncService : do Something2: 계정 줄이기
2023-02-06 00:27:42.238 INFO 5672 --- [ do-something-1] x.gits.boot.system.service.AsyncService : do Something1: 주문 생성
@ Async 주석은 다음 시나리오에서 실패합니다. 즉, @Async 주석은 명확하게 사용되지만 멀티스레딩은 사용되지 않습니다.
비동기 메서드는 정적 키워드로 수정됩니다.
비동기 클래스는 Spring 컨테이너의 Bean이 아닙니다(보통 @Component 및 @Service로 주석이 추가되고 Spring에서 검색할 수 있음). SpringBoot 애플리케이션에서는 사용할 수 없습니다. @EnableAsync 주석을 추가합니다.
동일한 클래스에서 메서드가 @Async로 주석이 달린 다른 메서드를 호출하면 해당 주석이 적용되지 않습니다. 그 이유는 @Async라는 어노테이션이 붙은 메소드가 프록시 클래스에서 실행되기 때문이다.
주의해야 할 점: @Async 주석을 사용하는 비동기 메서드의 반환 값은 void 또는 Future 및 해당 하위 클래스일 수 있습니다. 반환 결과가 다른 유형인 경우 메서드는 여전히 비동기적으로 실행됩니다. 반환값은 null이 됩니다.
위 내용은 SpringBoot에서 멀티스레딩을 우아하게 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!