๋งค์ผ๋ฉ์ผ ๋ฐฑ์๋ ์ง๋ฌธ์ ์ฐธ๊ณ ํด ๊ฐ์ธ์ ์ผ๋ก ํ์ตํ ๋ด์ฉ์ ์ ๋ฆฌํ์์ต๋๋ค.
์ค๋ฅ๊ฐ ์๋ค๋ฉด ์ธ์ ๋ ํผ๋๋ฐฑ ์ฃผ์๋ฉด ๋ฐ๋ก ๋ฐ์ํ๊ฒ ์ต๋๋ค..!
๋๊ธฐ(Synchronous) vs ๋น๋๊ธฐ(Asynchronous)
๋๊ธฐ(Synchronous): ํจ์ A๊ฐ ํจ์ B๋ฅผ ํธ์ถํ๋ฉด, A๋ B์ ์์ ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์
=> B์ ์์ ์ด ์๋ฃ๋๊ณ ๊ฒฐ๊ณผ๊ฐ์ด ๋ฐํ๋ ํ์์ผ A๋ ๋ค์ ์์ ์ ์ด์ด์ ์ํํ ์ ์์
(๋ชจ๋ ์์ ์ด ์์ฐจ์ ์ผ๋ก ์งํ)
๋น๋๊ธฐ(Asynchronous): ํจ์ A๊ฐ ํจ์ B๋ฅผ ํธ์ถํ ๋, A๋ B์ ์์ ์๋ฃ ์ฌ๋ถ๋ฅผ ์ ๊ฒฝ ์ฐ์ง ์๊ณ ์ฆ์ ๋ค์ ์ฝ๋๋ฅผ ์คํํ๋ ๊ฒ์
=> B๋ ๋ณ๋์ ํ๋ฆ์์ ์์
์ ์ํํ๋ฉฐ, ์์
์ด ์๋ฃ๋๋ฉด ์ฝ๋ฐฑ(Callback), ์ด๋ฒคํธ(Event), ๋๋ ๋ค๋ฅธ ๋ฉ์ปค๋์ฆ์ ํตํด A์๊ฒ ๊ฒฐ๊ณผ๋ฅผ ์๋ฆผ
(์์
์ด ์์ฐจ์ ์ผ๋ก ์งํ๋์ง X)
์ด ๋์ ์ฐจ์ด๋ ํธ์ถํ๋ ํจ์(Caller)๊ฐ ํธ์ถ๋ฐ๋ ํจ์(Callee)์ ์์ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋์ง ์ฌ๋ถ์
=> ์ฆ, ๊ฒฐ๊ณผ๋ฅผ ๋๋ ค๋ฐ๋ ์์ ๊ณผ ์์ ํ๋ฆ์ ์์์ ๋ํ ๊ด์ ์ผ๋ก ๋ณผ ์ ์์
๋ธ๋กํน(Blocking) vs ๋ ผ๋ธ๋กํน(Non-Blocking)
๋ธ๋กํน(Blocking): ํจ์ A๊ฐ ํจ์ B๋ฅผ ํธ์ถํ๋ฉด, ์ ์ด๊ถ์ด B๋ก ๋์ด๊ฐ๋ ๊ฒ์
=> B๊ฐ ์์ ์ ๋ชจ๋ ๋ง์น๊ณ ์ ์ด๊ถ์ ๋ฐํํ ๋๊น์ง A๋ ์คํ์ ๋ฉ์ถ๊ณ ๋๊ธฐ ์ํ(Blocked)์ ๋น ์ง
๋ ผ๋ธ๋กํน(Non-Blocking): ํจ์ A๊ฐ ํจ์ B๋ฅผ ํธ์ถํ๋ฉด, B๋ ์์ ์ ์์ํ๊ณ ์ฆ์ ์ ์ด๊ถ์ A์๊ฒ ๋ฐํํ๋ ๊ฒ์
=> A๋ B์ ์์ ์๋ฃ ์ฌ๋ถ์ ์๊ด์์ด ์์ ์ ์ฝ๋๋ฅผ ๊ณ์ํด์ ์คํํ ์ ์์
์ด ๋์ ์ฐจ์ด๋ ํธ์ถํ๋ ํจ์๊ฐ ํธ์ถ๋ฐ๋ ํจ์๋ฅผ ๋ถ๋ฅธ ์งํ ์ ์ด๊ถ์ ๋๋ ค๋ฐ์ ์ ์๋์ง ์ฌ๋ถ์
=> ์ฆ, ์ ์ด๊ถ์ ์์ ์ ๋ํ ๊ด์ ์ผ๋ก ๋ณผ ์ ์์
์์๋ก ์ดํด๋ณด๊ธฐ
์นดํ์์ ์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๋ ์ํฉ์ผ๋ก ์ ์กฐํฉ๋ค์ ์ดํด๋ณด๋ฉด
1. ๋๊ธฐ-๋ธ๋กํน (Sync-Blocking)
์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๊ณ , ์ปคํผ๊ฐ ๋์ฌ ๋๊น์ง ์นด์ดํฐ ์์์ ์๋ฌด๊ฒ๋ ๋ชป ํ๊ณ ๊ณ์ ๊ธฐ๋ค๋ฆผ
=> ์์ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ(๋๊ธฐ), ์ ์ด๊ถ๋ ๋์ด๊ฐ์ ๋ฉ์ถฐ์์(๋ธ๋กํน)
2. ๋๊ธฐ-๋ ผ๋ธ๋กํน (Sync-Non-Blocking)
์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๊ณ ์ ์ด๊ถ์ ๋ฐ๋ก ๋๋ ค๋ฐ์์ง๋ง(๋
ผ๋ธ๋กํน), ์ปคํผ๊ฐ ์ธ์ ๋์ค๋์ง ๊ถ๊ธํด์ 1์ด๋ง๋ค "์ ์ปคํผ ๋์๋์?"๋ผ๊ณ ๊ณ์ ๋ฌผ์ด๋ด
=> ์์
์๋ฃ๋ฅผ ์ง์ ๊ณ์ ํ์ธํด์ผ ํ๋ฏ๋ก(๋๊ธฐ), ๋ค๋ฅธ ์ค์ํ ์ผ์ ํ์ง๋ ๋ชปํจ
(์ ์ด๊ถ์ ๋ฐ๋ก ๋ฐ์ง๋ง, ๋๊ธฐ์ด๊ธฐ ๋๋ฌธ์ ๋ด๊ฐ ์ง์ ์๋ฃ ์ฌ๋ถ๋ฅผ ์ฒดํฌํด์ผ ํจ)
3. ๋น๋๊ธฐ-๋ธ๋กํน (Async-Blocking)
์ปคํผ ์ฃผ๋ฌธ์ ๋งค๋์ ์๊ฒ ์์(๋น๋๊ธฐ ํธ์ถ)ํ๊ณ ๋ค๋ฅธ ์ผ์ ๋ณด๋ ค ํ์ง๋ง, ๊ทธ ๋งค๋์ ๊ฐ ์ปคํผ๊ฐ ๋์ฌ ๋๊น์ง ์นด์ดํฐ ์์์ ํ์ผ์์ด ๊ธฐ๋ค๋ฆผ(๋ธ๋กํน)
=> ํธ์ถ ์์ฒด๋ ๋น๋๊ธฐ์ ์ด์์ผ๋, ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์ผ ํ๋ ๋ค๋ฅธ ์ฃผ์ฒด๊ฐ ๋ธ๋กํน๋๋ ํน์ดํ ๊ฒฝ์ฐ์
Java์ Future.get()
Java์์ Future.get()์ด ๋ํ์ ์ธ ์์์ธ๋ฐ Future.get()์ ๋น๋๊ธฐ๋ก ์คํํ ์์
์ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฉ์๋์
=> ๊ฒฐ๊ณผ๊ฐ ์์ง ์ ๋์์ผ๋ฉด ๊ทธ ์๋ฆฌ์์ ๊ธฐ๋ค๋ฆฌ๋(๋ธ๋กํน) ํน์ง์ด ์์
๊ฐ๋จํ๊ฒ ํ๋ฆ์ ์ดํด๋ณด๋ฉด
Future ๊ฐ์ฒด๋ ExecutorService.submit() ๊ฐ์ ๋น๋๊ธฐ ์์ ์ ์ถ ๊ฒฐ๊ณผ๋ก ๋ฐํ๋จ
ExecutorService.submit()์ ํธ์ถํ๋ฉด ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋(์ค๋ ๋ ํ ๋ด๋ถ ์ค๋ ๋)์์ ์คํํ๋๋ก ์์ฝํ๋๋ฐ ์ด๋ ๋ฐํ๋๋ ๊ฒ Future ๊ฐ์ฒด์
=> ์ด Future๋ "์์ง ๊ฒฐ๊ณผ๊ฐ ์ ๋์์ง๋ง, ๋์ค์ ์ด๊ฑธ ํตํด ๊ฒฐ๊ณผ๋ฅผ ๊บผ๋ผ ์ ์๋ค"๋ Promise ๊ฐ์ ์ญํ ์ ํจ
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {
Thread.sleep(2000); // 2์ด ๊ฑธ๋ฆฌ๋ ์์
return "์ปคํผ ์์ฑ!";
});
System.out.println("๋ค๋ฅธ ์ผ ํ๋ ์ค...");
String result = future.get(); // ๊ฒฐ๊ณผ ๋์ฌ ๋๊น์ง ๋ธ๋กํน
System.out.println(result);
executor.shutdown();
ํธ์ถ ์์ฒด๋ ๋น๋๊ธฐ(์์ ์ ๋ณ๋ ์ค๋ ๋์์ ์คํ)์ง๋ง get()์ ๊ฒฐ๊ณผ ๋ฐ์ ๋๊น์ง ํ์ฌ ์ค๋ ๋(ํธ์ถํ ์ค๋ ๋)๋ฅผ ๋ธ๋กํนํ๊ธฐ์ ๋น๋๊ธฐ + ๋ธ๋กํน์ด๋ผ๋ ํน์ดํ ์กฐํฉ์ด ๋จ
(์์ ์คํ ์ค๋ ๋๋ ๊ณ์ ์ผํ๊ณ ์๊ณ ํธ์ถํ ์ชฝ ์ค๋ ๋๋ get()์์ ๋ฉ์ถฐ์ ๊ธฐ๋ค๋ฆผ)
4. ๋น๋๊ธฐ-๋ ผ๋ธ๋กํน (Async-Non-Blocking)
์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๊ณ ์ง๋๋ฒจ์ ๋ฐ์์ ์๋ฆฌ์์ ์์ ๋กญ๊ฒ ํ ๊ฑธ ํจ(๋ ผ๋ธ๋กํน) ๊ทธ๋ฌ๋ค ๋์ค์ ์ง๋๋ฒจ์ด ์ธ๋ฆฌ๋ฉด(Callback), ๊ทธ๋ ์ปคํผ๋ฅผ ์ฐพ์ผ๋ฌ ๊ฐ
=> ์์ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ (๋น๋๊ธฐ), ์ ์ด๊ถ๋ ๋ฐ๋ก ๋๋ ค๋ฐ์
Spring์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ (@Async)
Spring์์๋ @Async ์ด๋ ธํ ์ด์ ์ ํตํด ๋น๋๊ธฐ-๋ ผ๋ธ๋กํน ํจํด์ ๋งค์ฐ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์์
=> ํ์๊ฐ์ ํ ์ด๋ฉ์ผ ๋ฐ์ก, ํธ์ ์๋ฆผ, ๋์ฉ๋ ํ์ผ ์ฒ๋ฆฌ ๋ฑ ์ฆ๊ฐ์ ์ธ ์๋ต์ด ํ์ ์๋ ์์ ์ ๋น๋๊ธฐ๋ก ์ ํํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์
์ฌ์ฉ๋ฒ
- ๋น๋๊ธฐ ๊ธฐ๋ฅ ํ์ฑํ: @Configuration ํด๋์ค์ @EnableAsync๋ฅผ ์ถ๊ฐํฉ๋๋ค.
import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; @Configuration @EnableAsync public class AsyncConfig { // (ํ์ ์ ์ค๋ ๋ ํ ์ปค์คํฐ๋ง์ด์ง) } - @Async ์ ์ฉ: ๋น๋๊ธฐ๋ก ์คํํ public ๋ฉ์๋์ @Async๋ฅผ ๋ถ์ฌ์ค๋๋ค.
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class NotificationService { @Async public void sendWelcomeEmail(String email) { System.out.println(Thread.currentThread().getName() + "์์ ํ์ ์ด๋ฉ์ผ ๋ฐ์ก ์์..."); try { Thread.sleep(3000); // 3์ด๊ฐ ๊ฑธ๋ฆฌ๋ ์์ ์ด๋ผ ๊ฐ์ } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println(email + "๋์๊ฒ ํ์ ์ด๋ฉ์ผ ๋ฐ์ก ์๋ฃ!"); } }
์ด์ ๋ค๋ฅธ ๊ณณ์์ sendWelcomeEmail ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด, Spring์ ์ด ๋ฉ์๋๋ฅผ ๋ณ๋์ ์ค๋ ๋์์ ์คํํ๊ณ ์ฆ์ ๋ค์ ์ฝ๋๋ก ๋์ด๊ฐ
@Async ์ฌ์ฉ ์ ๋ฐ๋์ ์์์ผ ํ ์ฃผ์์ฌํญ
1. ์์ธ(Exception)๋ ํธ์ถ์์๊ฒ ์ ํ๋์ง ์๋๋ค
@Async
public void asyncJob() {
throw new RuntimeException("๋ฌธ์ ๋ฐ์!");
}
public void caller() {
try {
asyncJob();
} catch(Exception e) {
System.out.println("์กํ๋?"); // X, ์กํ์ง ์์
}
}
@Async๊ฐ ์ ์ฉ๋ ๋ฉ์๋๋ ๋ณ๋์ ์ค๋ ๋์์ ๋์ํ๊ธฐ ๋๋ฌธ์, ๋ด๋ถ์์ ๋ฐ์ํ ์์ธ๋ ํธ์ถ์(Caller)์ try-catch ๋ธ๋ก์ ์กํ์ง ์์
ํด๊ฒฐ์ฑ
@Async
public Future<String> asyncJob() {
if(true) throw new RuntimeException("๋ฌธ์ ๋ฐ์");
return new AsyncResult<>("OK");
}
Future<String> future = asyncJob();
try {
future.get(); // ์ด ์์ ์์ ์์ธ๋ฅผ ๋ฐ์ ์ ์์
} catch(Exception e) { ... }
- Future ๋๋ CompletableFuture ์ฌ์ฉ: ๋ฐํ ํ์ ์ Future<T>๋ CompletableFuture<T>๋ก ์ค์ ํ๋ฉด ๋น๋๊ธฐ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ์ถ์ ํ๊ณ .get() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์์ ์ ์์ธ๋ฅผ ๋ฐ์ ์ ์์
- AsyncUncaughtExceptionHandler ๊ตฌํ: void๋ฅผ ๋ฐํํ๋ ๋น๋๊ธฐ ๋ฉ์๋์ ์์ธ๋ฅผ ์ ์ญ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ํธ๋ค๋ฌ๋ฅผ ์ง์ ๊ตฌํํ ์ ์์
2. ํ๋ก์(Proxy) ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ค
@Async๋ Spring AOP(Aspect-Oriented Programming) ํ๋ก์๋ฅผ ํตํด ๋์ํจ
์คํ๋ง์ด @Async๊ฐ ๋ถ์ ๋น์ ๋ง๋ค ๋, ์ค์ ๊ฐ์ฒด ๋์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํ๊ณ ๋ค๋ฅธ ์ฝ๋์์ ํ๋ก์๋ฅผ ํธ์ถํ๋ฉด ํ๋ก์๊ฐ ํธ์ถ์ ๊ฐ๋ก์ฑ
(์ดํ๋ฆฌ์ผ์ด์ ์ฝ๋์์ @Autowired์ ๊ฐ์ด ์์กด์ฑ์ ์ฃผ์ ๋ฐ์ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ Spring์ ์ค์ฒด ๊ฐ์ฒด๊ฐ ์๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํด์ค)
=> @Async๋ฅผ ํ์ธํ๊ณ ๋ณ๋ ์ค๋ ๋์์ ์คํ ํ ์๋ ๋ฉ์๋๋ก ์ ๋ฌ
(์ฆ, @Async๋ ์ค์ ๋ฉ์๋๊ฐ ์๋๋ผ ํ๋ก์๊ฐ ๋์ ์คํํ๋ ๊ตฌ์กฐ์)
์ด์ ๊ฐ์ด AOP ํ๋ก์๋ฅผ ํตํด ๋์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ ํด๋์ค ๋ด๋ถ์์ @Async ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถ(this.method())ํ๋ฉด ๋น๋๊ธฐ๋ก ๋์ํ์ง ์์
=> ํ๋ก์๋ฅผ ๊ฑฐ์น์ง ์๊ณ ์ค์ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ๋๋ฌธ
์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ฒด ํธ์ถ์ ๋์ ์ฒ๋ฆฌ๋ง ํ๋ ํ๋ก์์ ๋ค๋ฅด๊ฒ AOP ํ๋ก์๋ ๊ฐ์ฒด ํธ์ถ ์ ํ๋ก ๊ณตํต ๊ธฐ๋ฅ์ ์ ์ฉํ ์ ์์
=> @Async๊ฐ ๋์ํ๋ ค๋ฉด ์ค๋ ๋ ํ์์ ์คํํ๋ผ๋ Advice๋ฅผ ๋ฃ์ ์ ์๊ฒ AOP ํ๋ก์๋ฅผ ๊ฑฐ์ณ์ผํจ
ํด๊ฒฐ์ฑ
- ํด๋์ค ๋ถ๋ฆฌ: @Async ๋ฉ์๋๋ฅผ ๋ณ๋์ ํด๋์ค๋ก ๋ถ๋ฆฌํ๊ณ , ํด๋น ํด๋์ค๋ฅผ ์ฃผ์
(DI)๋ฐ์ ํธ์ถํ๋ ๊ฒ์ด ๊ฐ์ฅ ๋ช
ํํ๊ณ ์ข์ ๋ฐฉ๋ฒ์
- ์๊ธฐ ์์ ์ฃผ์ : ์๊ธฐ ์์ ํ์ ์ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ๋ฐ์ ํ๋ก์๋ฅผ ํตํด ํธ์ถํ๋ ๋ฐฉ๋ฒ๋ ๊ฐ๋ฅ
3. ํธ๋์ญ์ ์ ์๋ช ์ฃผ๊ธฐ๋ ๋ถ๋ฆฌ๋๋ค
@Async ๋ฉ์๋๋ ์๋ก์ด ์ค๋ ๋์์ ๋์ํ๊ธฐ ๋๋ฌธ์ ํธ์ถ์ ์ค๋ ๋์ ํธ๋์ญ์ ์ปจํ ์คํธ๋ฅผ ์ด์ด๋ฐ์ง ์์
ํธ๋์ญ์ ์ปจํ ์คํธ๋ ํธ๋์ญ์ ์ ๋ณด๋ฅผ ๋ด์ ์ค๋ ๋ ๋จ์ ์ํ๋ก Spring์์ ํธ๋์ญ์ ์ ์ค๋ ๋-๋ก์ปฌ(ThreadLocal)๋ก ๊ด๋ฆฌ๋จ
=> ์ฆ, ๋น๋๊ธฐ ๋ฉ์๋ ๋ด์์ ์์ฑํ ํธ๋์ญ์
์ ์์ ํธ๋์ญ์
๊ณผ ๋ฌด๊ดํ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง
(ํธ์ถ์์ ํธ๋์ญ์
์ด ๋กค๋ฐฑ๋์ด๋ ๋น๋๊ธฐ ๋ฉ์๋์ ํธ๋์ญ์
์ ์ปค๋ฐ๋ ์ ์์)
๋น๋๊ธฐ ์์ ์ด ๋ฐ๋์ ํธ๋์ญ์ ์ ํ์๋ก ํ๋ค๋ฉด, @Async ๋ฉ์๋์ ์ง์ @Transactional ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ ์๋ก์ด ํธ๋์ญ์ ์ ์์ํด์ผํจ
'๐ป CS > ๋งค์ผ๋ฉ์ผ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ์ฌ์ฉ์๊ฐ ์น์ฌ์ดํธ์ ์ฒ์ ์ ๊ทผํ ๋์ ๊ณผ์ (0) | 2025.08.24 |
|---|---|
| TCP 3-way handshake & 4-way handshake (6) | 2025.08.14 |
| ๋์ผ์ฑ๊ณผ ๋๋ฑ์ฑ : == ์ equals() (3) | 2025.08.08 |
| ํฐ์บฃ(Tomcat)์ด๋? (5) | 2025.08.05 |
| ์์ ๋ณต์ฌ์ ๊น์ ๋ณต์ฌ์ ์ฐจ์ด (4) | 2025.08.04 |