@Async Annotation을 활용하면 비동기 메소드를 손쉽게 작성할 수 있다.
@Async 어노테이션이 선언된 메소드는 비동기 메소드로 동작하게 된다. (AOP)
@Async 어노테이션이 선언된 메소드는 리턴 타입에 따라 내부적으로 상이하게 동작한다.
- void :
별도의 쓰레드로 실행되며, 리턴이 없으므로 결과를 기다리지 않고 다음 로직이 수행된다. ThreadPoolTaskExcutor에 의해 자동으로 스레드를 새로 생성해서 비동기 블록 로직을 수행한다.
logger.info(“start”)
@Async
public void t1 (){
logger.info(“start async logic”)
Thread.sleep(1000);
logger.info(“end async logic”)
}
logger.info(“non-blocking”)
[logger]
>start
>non-blocking
>start async logic
>end async logic - Future :
리턴값을 받아야 한다면 Future 를 이용해야 한다.
@Async
public Future<Integer> methodName(String name) throws InterruptedException{
logger.info(“start async logic”)
…
return new AsyncResult<>(“return”);
}
//caller 쪽에서는 아래와 같이 작성한다.
Future<Integer> future = instanceName.methodName(“param”)
logger.(future.get())
future의 get 메소드는 메소드의 결과를 받을 때까지 계속기다린다.
메소드가 완료될때까지 기다린다. (블로킹이 발생한다.) - ListenableFuture :
@Async
public ListenalbleFuture<Integer> methodName(String name) throws InterruptedException{
logger.info(“start async logic”)
…
return new AsyncResult<>(“return”);
}
//caller
ListenableFuture<Integer> future = instanceName.methodName(“param”)
future.addCallback(s -> logger.info(“retuen string is ”) + s);
logger.info(“non-blocking”)
[logger]
>non-blocking
>start async logic
>retuen string is return
future.addcallback 은 비동기 메서드 내부 로직이 완료되면 수행되는 콜백기능이다.
위 future.get은 리턴을 받을 때까지 기다리지만 (block) callback 을 넣으면
아래 로직을 타다가 리턴을 받을 때 실행된다. - CompletableFuture :
@Async
public CompletableFuture<Integer> methodName(String name){
logger.info(“start method ” + name);
Thread.sleep(3000);
logger.info(“end method ” + name);
return new AsyncResult<> (“ returns”).completable()
}
get 메서드 사용
completable 메소드를 사용하면 CompletableFuture로 리턴할 수 있다.
//caller
CompletableFuture<Integer> future = instanceName.methodName(“param”);
logger.info(“non-blocking”);
logger.info(“blocking : ” + future.get());
logger.info(“after blocking”);
[logger]
>non-blocking
>start method param
>end method param
>blocking : returns
>after blocking
Future와 마찬가지로 get 메소드 리턴값을 받을 때까지 블로킹이 발생한다.
Completable method 는 메인쓰레드가 아닌 별도의 쓰레드로 동작한다.
메인 쓰레드는 methodName을 실행한 후 잠시동안 논블로킹으로 동작한다.
따라서 메소드 내부의 로그가 찍히기 전에 non-blocking 로그가 먼저 찍히고
get 메서드를 실행하게 되는 시점에 다시 블로킹된다.
callback 메서드 사용
전체 과정을 non blocking으로 동작하게 하고 싶다면 callback을 쓴다.
CompletableFuture 에서 제공하는 thenAccept 를 쓰면 된다.
//caller
CompletableFuture<Integer> future = instanceName.methodName(“param”);
logger.info(“11non-blocking”);
future.thenAccept(p -> logger.info(“callback massege” + p) );
logger.info(“22non-blocking”);
[logger]
>11non-blocking
>22non-blocking
>start method param
>end method param
>callbackmassege returns
이는 메인쓰레드는 완벽히 논블로킹으로 작동하고
thenAccept는 별개 스레드로 동작하게 된다.
REFERANCE : https://brunch.co.kr/@springboot/401
'일 > java' 카테고리의 다른 글
Java 비동기 서버 Trouble Shooting :: Heap MEM, Thread Pool (0) | 2022.02.21 |
---|---|
java 동시성 제어 (0) | 2022.02.09 |