๐ก ์ด ๊ธ์ ํ์ฌ ์ธํด ๊ธฐ๊ฐ์ ์คํฐ๋ํ ๋ด์ฉ์ ์ ๋ฆฌํ ๊ธ์ ๋๋ค!
์ฐ๋ ๋ํ(Thread Pool)์ ์ ์ํ๊ธฐ์ ์์ ๋ฌธ์ ์ํฉ ํ๋๋ฅผ ๋จผ์ ์๊ฐํด๋ณด์.
์ฌ์ฉ์ ์์ฒญ์ด ๋ค์ด์ฌ ๋๋ง๋ค ์ฐ๋ ๋๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค!
์ด๋ฐ ๊ตฌ์กฐ๋ ํนํ ์น์์ ๋งค์ฐ ํํ๋ค.
์ฌ์ฉ์ ์์ฒญ๋ง๋ค ์ฐ๋ ๋๋ฅผ ์๋ก ๋ง๋ค์ด์ ์์
์ ์ํํ๋๋ก ๊ตฌํํ๋ค.
๋ง์ฝ ์ฌ์ฉ์ ์์ฒญ์ด ๋ง์์ง๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
์ฐ๋ ๋๊ฐ ๋๋ฌด ๋ง์์ ธ์ ํ๋ก๊ทธ๋จ์ด ์์์น ๋ชปํ ๋์์ ํ ์ ์๋ค.
์ฌํ ๊ฒฝ์ฐ ํ๋ก๊ทธ๋จ์ด ์ข
๋ฃ๋๋ค..!
๊ทธ๋์ ์ฐ๋ ๋ํ(Thread Pool)์ ์ฌ์ฉํด ์ด๋ฐ ์ํฉ์ ์๋ฐฉํ๋ค.
๊ฐ๋ฐ ๋ถ์ผ์์๋ Pool์ด๋ผ๋ ๋จ์ด๊ฐ ํํ๊ฒ ์ฌ์ฉ๋๋ค.(Connection Pool, Thread Pool ...)
๊ฐ๋ฐ ๋ถ์ผ์์ Pool์ด๋, ์ด๋ค ๋์์ Pool์ ์ฌ๋ฌ๊ฐ ๋ฃ์ด๋๊ณ ๊ด๋ฆฌํ๋ ๋๋์ผ๋ก ์ฌ์ฉํ๋ค.
๊ทธ๋์ ์ฐ๋ ๋ํ(Thread Pool)๋ ์ฌ๋ฌ ์ฐ๋ ๋๋ฅผ Pool์ ๋ฃ์ด๋๊ณ ๊ด๋ฆฌํ๋ฉฐ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋ค.
์ฐ๋ ๋ํ์๋ ์ฐ๋ ๋ ๊ฐฏ์์ ์ต์๊ฐ๊ณผ ์ต๋๊ฐ์ ์ง์ ํ ์ ์๋ค.
์ฐ๋ ๋ํ์ ์ต์๊ฐ๋งํผ์ ์ฐ๋ ๋๋ฅผ ํ๋ก๊ทธ๋จ์ด ๊ธฐ๋๋ ๋ ๋ฏธ๋ฆฌ ์์ฑํ๋ค.
์ด ์ฐ๋ ๋๋ค์ ๊ณ์ ๊ฐ์ง๊ณ ์๋ค๊ฐ ์์
์ด ๋ค์ด์ค๋ฉด ํ ๋นํ๊ธฐ ๋๋ฌธ์ ์ฐ๋ ๋๋ฅผ ์๋ก ์์ฑ/์ญ์ ํ๋ ๋น์ฉ์ด ์ค์ด๋ ๋ค.
์์์ ์ค๋ช
ํ๋ฏ์ด ์ฐ๋ ๋ํ์ ์ฐ๋ ๋ ๊ฐฏ์๋ฅผ ์กฐ์ ํ ์ ์๋ค.
์ฐ๋ ๋ ๊ฐฏ์๋ฅผ ๋ง๊ฒ ํ๋ฉด ์์ฒญ์ด ๋ง์์ก์ ๋ ๋ถํ๋ฅผ ์ค์ผ ์ ์๋ค.
์ฐ๋ ๋ ๊ฐฏ์๋ฅผ ์ ๊ฒ ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ ์ ์๋ค.
ํ๋ก๊ทธ๋จ์ ํน์ฑ์ ๋ง๊ฒ ์์
์ ์ ์ดํ ์ ์๋ค.
๋ค์์ ์ค๋ช ํ ์ฌ๋ฌ ์ต์ ์ ํ์ฉํ์ฌ ์ฐ๋ ๋์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ค.
1๋ถ ๊ฑธ๋ฆฌ๋ ์์
๊ณผ 1์ด ๊ฑธ๋ฆฌ๋ ์์
์ด ์์ฌ์ ์ฐ๋ ๋ํ์ ์ฌ์ฉํ ํ๋ก๊ทธ๋จ์ ๋ค์ด์จ๋ค๊ณ ์๊ฐํด๋ณด์.
์๊ฐ์ด ์ข ์ง๋๊ณ ๋๋ฉด ์ฐ๋ ๋ํ์ ์ฐ๋ ๋๋ค์ ๋ชจ๋ 1๋ถ ๊ฑธ๋ฆฌ๋ ์์
์ด ์งํ์ค์ผ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ฉด ๊ทธ ๋ค์ ๋ค์ด์ค๋ 1์ด ๊ฑธ๋ฆฌ๋ ์์
๋ค์ ์ค์ ์์
์๊ฐ๋ณด๋ค ํจ์ฌ ๊ธด ์๊ฐ์ ๋๊ธฐ์๊ฐ์ผ๋ก ์๋ชจํ๊ฒ ๋๋ค.
์ด๋ ๊ฒ ์์ ์ ํฌ๊ธฐ๊ฐ ์ฐจ์ด๋๋ ์์ ๋ค์ด ์์ฌ ๋ค์ด์ฌ ๊ฒฝ์ฐ ๋นํจ์จ์ด ๋ฐ์ํ ์ ์๋ค.
์ด๊ฑด ์ฐ๋ ๋ํ์ ๋จ์ ์ด๋ผ๊ธฐ๋ณด๋ค๋ ๋ฉํฐ์ฐ๋ ๋ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ์ ์ธ ์ฃผ์์ ์ด๋ค.
๊ฐ ์ฐ๋ ๋๊ฐ ์ํํ๋ ์์
๊ฐ์ ์์กด์ฑ์ด ์กด์ฌํ๋ค๋ฉด ๋ฐ๋๋ฝ์ด ๋ฐ์ํ ์ ์๋ค.
์ ๋จ์ ์ ์กฐํฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๋ก ์ ๋ด๋ฆด ์ ์๋ค.
์ฐ๋ ๋ํ์ ์คํ ๊ท๋ชจ๊ฐ ๋น์ทํ๊ณ ์๋ก ๋ ๋ฆฝ์ ์ธ ์์ ์ผ ๋ ์ฌ์ฉํ๊ธฐ ์ข๋ค!
์ฆ, ์น ๊ฐ๋ฐ์์ ์ฌ์ฉํ๊ธฐ ์ข๋ค.
Java์์๋ java.util.concurrent
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํด ์ฐ๋ ๋ํ์ ๊ด๋ฆฌํ ์ ์๋ค.
Spring์์๋ ThreadPoolTaskExecutor
ํ๋ ์์ํฌ๋ฅผ ํ์ฉํด ์ฐ๋ ๋ํ์ ๊ด๋ฆฌํ ์ ์๋ค.
Java์ ์ฐ๋ ๋ํ ๊ด๋ฆฌ๋ ๊ฒฝ๋์ด๋ฉฐ ํ๋ ์์ํฌ ์์กด์ฑ์ด ๋ฎ์ ๊ฒ ์ฅ์ ์ด๋ค.
Spring์ ์ฐ๋ ๋ํ ๊ด๋ฆฌ๋ ์ฌ๋ฌ ์ด๋
ธํ
์ด์
๊ณผ ํตํฉํ ์ ์๊ณ ์ด๋ฅผ ํตํด ์์ค ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ์์ฑํ ์ ์๋ ๊ฒ ์ฅ์ ์ด๋ค.
์ฐ๋ฆฌ๋ Spring ๊ด์ ์์ ์ข ๋ ์์ธํ ๋ค์ฌ๋ค๋ณด์.
TaskExecutor์ ๋ํด์ ๋จผ์ ์์๋ณด์.
TaskExecutor๋ Spring์์ ๋น๋๊ธฐ ์์
์คํ์ ์ถ์ํํ ์ธํฐํ์ด์ค์
๋๋ค.
๊ตฌํ์ฒด๋ก๋ ๋ค์๊ณผ ๊ฐ์ ์ข
๋ฅ๊ฐ ์๋ค.
SimpleAsyncTaskExecutor๋ Spring์์ ๋น๋๊ธฐ๋ฅผ ์ํํ ๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ค์ ๋๋ TaskExecutor์ด๋ค.
SimpleAsyncTaskExecutor๋ ์์ฒญ์ด ๋ค์ด์ฌ ๋๋ง๋ค ์ฐ๋ ๋๋ฅผ ์์ฑํ๋ค.
์ต๋ ์ฐ๋ ๋ ๊ฐฏ์๋ ์ค์ ํ ์ ์์ง๋ง ๊ทธ ์ธ์ ์์ธํ ์ค์ ์ ์ด๋ ค์์ TreadPoolTaskExecutor๋ฅผ ์ฌ์ฉํ๊ธฐ๋ฅผ ๊ถ์ฅํ๋ค.
TaskExecutor๋ ๋น๋๊ธฐ ์์
์คํ์ ํ๊ธฐ ์ํด ๋ง๋ค์ด์ก๋ค.
@Async
์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ ๋ฉ์๋๋ ๋ค๋ฅธ ์ฐ๋ ๋์์ ๋น๋๊ธฐ๋ก ์คํ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก๋ SimpleAsyncTaskExecutor๋ฅผ ์ด์ฉํด ์ฐ๋ ๋๋ฅผ ๊ด๋ฆฌํ์ง๋ง Param์ ํตํด ํน์ TaskExecutor๋ฅผ ์ง์ ํ ์ ์๋ค.
@Configuration
@EnableAsync
public class ThreadPoolConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("Thread-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(30);
executor.initialize();
return executor;
}
}
์ ์ฝ๋๋ Config ํด๋์ค๋ค.
@Bean
์ด๋
ธํ
์ด์
์ผ๋ก ์ด๋ฆ์ ์ง์ ํด์ taskExecutor๋ฅผ ์์ฑํ๊ณ ์๋ค.
์ฌ๋ฌ ์ค์ ์ด ๋ณด์ด๋๋ฐ ์ด๋ 2.4 ์ต์
๋ฐ ์ค์ ์์ ์์ธํ ๋ณด๋๋ก ํ์.
@RestController
public class ThreadPoolController {
@Autowired
private ThreadPoolService threadPoolService;
@GetMapping("/start-tasks")
public String startTasks(@RequestParam(defaultValue = "10") int taskCount) {
for (int i = 0; i < taskCount; i++) {
threadPoolService.executeTask("Task " + i);
}
return taskCount + " Tasks done!";
}
}
์๋ Controller ์ฝ๋์ด๋ค.
Service์ executeTask()
๋ฉ์๋๋ฅผ ๋ฐ๋ณตํด์ ํธ์ถํ๊ณ ์๋ค.
ํด๋น ๋ฉ์๋๋ ๋น๋๊ธฐ๋ก ThreadPoolTaskExecutor๋ฅผ ํ์ฉํด ๋ฉํฐ์ฐ๋ ๋ ์์
์ ํ๊ณ ์๋ค.
@Service
public class ThreadPoolService {
@Async("taskExecutor")
public void executeTask(String task) {
System.out.println(Thread.currentThread().getName() + " is processing " + task);
try {
Thread.sleep(2000); // Simulate task
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
์๋ Service ์ฝ๋์ด๋ค.
ThreadPoolTaskExecutor๋ฅผ ์ง์ ํด์ ๋น๋๊ธฐ๋ก ์์
ํ๋ค.
2์ด ๋๊ธฐ์ ๋ก๊ทธ๋ฅผ ์ฐ๋ ์์
์ ๋ฃ์ด ๋ฉํฐ์ฐ๋ ๋ ๋์์ ํ์ธํ ์ ์๋ค.
์ ์ฝ๋๋ฅผ ๋์ํ๋ฉด ๋ธ๋ผ์ฐ์ ์ ์ฝ์์์ ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์๋ค.
์ฌ๋ฌ ์ต์ ์ด ์์ง๋ง ๋ํ์ ์ธ 7๊ฐ์ง ์ต์ ๋ง ์ดํด๋ณด์.
๊ธฐ๋ณธ ์ฐ๋ ๋ ๊ฐฏ์๋ฅผ ์๋ฏธํ๋ค.
์ต์ ์ฐ๋ ๋ ๊ฐฏ์๋ก ์ดํดํ๋ฉด ๋๋ค.
ํ๋ก๊ทธ๋จ์ด ๊ตฌ๋๋ ๋ ์์ฑํ์ฌ ์ข
๋ฃ๋ ๋๊น์ง ์ ์ง๋๋ค.
๊ธฐ๋ณธ๊ฐ์ 1์ด๋ค.
์ต๋ ์ฐ๋ ๋ ๊ฐฏ์๋ฅผ ์๋ฏธํ๋ค.
corePoolSize๋งํผ์ ์ฐ๋ ๋๊ฐ ๋ชจ๋ ์์
์ค์ผ ๋ ์๋ก์ด ์์
์ด ๋ค์ด์ค๋ฉด ์ถ๊ฐ ์ฐ๋ ๋๋ฅผ ์์ฑํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ฐ๋ ๋๋ ๊ธฐ๋ณธ ์ฐ๋ ๋๊น์ง ํฌํจํด์ ์ต๋ MaxPoolSize๋งํผ ๊ฐ์ง๊ณ ์์ ์ ์๋ค.
๊ธฐ๋ณธ๊ฐ์ Integer.MAX_VALUE์ด๋ค.
ํ์ ์ฉ๋์ด๋ค.
์ฉ๋์ด ๊ฐ๋์ฐผ๋๋ฐ ์๋ก์ด ์์
์ ๋ฃ์ผ๋ ค๊ณ ํ๋ฉด RejectedExecutionHandler์ ์ ์๋ ์ ์ฑ
๋๋ก ํ๋ํ๋ค.
๊ธฐ๋ณธ๊ฐ์ Integer.MAX_VALUE์ด๋ค.
์ฐ๋ ๋์ ์ด๋ฆ์ ์ค์ ํ๋ค.
๊ธฐ๋ณธ๊ฐ์ ํด๋์ค ์ด๋ฆ์ด๋ค.
ํ ์ฉ๋์ ์ด๊ณผํ์ฌ ์์
์ด ์์ ๋, ์ฒ๋ฆฌ ์ ์ฑ
์ด๋ค.
์ ์ฑ
์ ๋ค์๊ณผ ๊ฐ์ ์ข
๋ฅ๊ฐ ์๋ค.
ํ๋์ฉ ์ดํด๋ณด์.
๊ฑฐ๋ถ ์ ์ฑ
์ด๋ค.
RejectedExecutionException์ ๋์ง๋ค.
์ด๋ฅผ ํตํด ์ฌ์ฉ์์๊ฒ ์๋ดํด์ ์๋ฒ ๋ถํ๋ฅผ ๋ง์ ์ ์๋ค.
์๋ก์ด ์์
์ ๊ฑฐ๋ถํ๋ค.
์์
์ ๋ฒ๋ฆฌ๊ณ ์์ธ๋ฅผ ๋ฐ์์ํค์ง ์๋๋ค.
ํ์์ ๊ฐ์ฅ ์ค๋๋ ์์
์ ๋ฒ๋ฆฐ๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ก์ด ์์
์ ํ์ ์ถ๊ฐํ๋ค.
์ต์ ์์ฒญ ์์ ์ด ๋ ์ค์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ค.
์์
์ ํธ์ถํ ์ฐ๋ ๋์์ ์ง์ ์คํํ๋ค.
๋ถํ๋ฅผ ์ข ๋ ์ ๋์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ค.
์ด๋ค ์์ ๋ ๋ฒ๋ ค์ง๊ธฐ๋ฅผ ์์น ์์ ๋ ์ฌ์ฉํ๋ค.
์ ํ๋ฆฌ์ผ์ด์
์ด ์ข
๋ฃ๋ ๋ ๋์์ ์ง์ ํ๋ค.
false(Default)์ธ ๊ฒฝ์ฐ, ์ ํ๋ฆฌ์ผ์ด์
์ด ์ฆ์ ์ข
๋ฃ๋๋ค.
true์ธ ๊ฒฝ์ฐ, ์ฐ๋ ๋์์ ์ํ์ค์ด๋ ์์
๊ณผ ํ์ ๋จ์ ์์
๊น์ง ๋ชจ๋ ์ํํ ํ ์ข
๋ฃ๋๋ค.
2.4.6 setWaitForTasksToCompleteOnShutdown๊ณผ ํจ๊ป ์ฌ์ฉ๋๋ค.
setWaitForTasksToCompleteOnShutdown ๊ฐ์ด true์ธ ๊ฒฝ์ฐ, ํ๋ก๊ทธ๋จ ์ข
๋ฃ๊น์ง ๋๊ธฐํ ์๊ฐ์ ์ง์ ํ๋ค.
๊ธฐ๋ณธ๊ฐ์ 0์ผ๋ก ์ฐ๋ ๋์์ ์ํ์ค์ด๋ ์์ ๊ณผ ํ์ ๋จ์ ์์ ์ด ๋ชจ๋ ๋๋ ๋๊น์ง ๋๊ธฐํ๋ค.