CS
[CS] 동시성과 병렬성의 개념
kahnco
2025. 4. 15. 11:55
반응형
이 글에서는 멀티스레드 프로그래밍의 핵심 개념인 동시성(Concurrency) 과 병렬성(Parallelism) 을 구체적으로 설명하고, Java Spring 프레임워크에서 이를 어떻게 확인하고 활용할 수 있는지 예제 코드와 함께 살펴본다.
📌 1. 동시성(Concurrency)이란?
동시성은 여러 작업이 논리적으로 동시에 실행되는 것처럼 보이도록 처리하는 방식을 의미한다.
▶︎ 동시성의 핵심 개념
- 단일 CPU에서도 구현 가능
- 여러 작업을 번갈아 실행하면서, 사용자는 작업이 동시에 이루어지고 있다고 느낀다.
- 컨텍스트 스위칭(Context Switching)을 활용하여 작업 간 전환이 빠르게 이루어진다.
▶︎ 동시성 예시
- 웹서버가 여러 클라이언트 요청을 동시에 처리하는 경우
- Java에서 여러 스레드(Thread)를 만들어 논리적인 병행 처리를 수행하는 경우
▶︎ 동시성의 장점
- 자원 활용을 극대화하여 작업의 응답성을 높임
- 대기 시간이 긴 I/O 작업을 수행할 때 효율적으로 활용 가능
📌 2. 병렬성(Parallelism)이란?
병렬성은 여러 작업이 물리적으로 동시에 수행되는 방식을 의미한다.
▶︎ 병렬성의 핵심 개념
- 반드시 다중 CPU 또는 다중 코어 환경이 필요하다.
- 각 작업이 서로 독립된 CPU 또는 코어에서 동시에 처리된다.
- 여러 작업을 동시에 처리하여 총 작업 시간을 줄인다.
▶︎ 병렬성 예시
- 멀티코어 환경에서의 데이터 처리 및 연산 작업
- Java의 병렬 스트림(Parallel Stream)을 이용하여 데이터를 병렬 처리하는 경우
▶︎ 병렬성의 장점
- 작업 속도가 빨라지고 처리량이 증가한다.
- CPU 집약적인 작업에서 성능 향상 효과가 크다.
📌 3. 동시성과 병렬성의 차이점 비교
구분 동시성 (Concurrency) 병렬성 (Parallelism)
정의 | 논리적으로 여러 작업이 동시에 실행 | 물리적으로 여러 작업이 동시에 실행 |
CPU 조건 | 단일 CPU에서도 가능 | 멀티 코어 CPU 필수 |
목적 | 응답성 향상, 자원 활용 최적화 | 처리 성능 향상, 처리 속도 증가 |
예시 | 웹서버의 멀티스레드 요청 처리 | 데이터 분석, 병렬 연산 처리 |
📌 4. Java Spring에서 동시성과 병렬성의 구현 예제
Spring에서는 비동기(@Async) 기능을 통해 손쉽게 동시성과 병렬성을 구현할 수 있다.
예제를 통해 실제로 이를 확인해보자.
✅ Spring 프로젝트에서 비동기 설정
@Async를 사용하기 위한 설정을 먼저 수행한다.
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("Async-Thread-");
executor.initialize();
return executor;
}
}
✅ 동시성(Concurrency) 예제
다수의 작업이 논리적으로 동시에 수행되는 모습을 확인한다.
비동기 서비스 클래스 작성:
@Service
public class ConcurrentService {
@Async("threadPoolTaskExecutor")
public void processTask(int taskNumber) throws InterruptedException {
System.out.println("작업 시작: " + taskNumber + " - 스레드: " + Thread.currentThread().getName());
Thread.sleep(3000); // 3초 지연
System.out.println("작업 완료: " + taskNumber + " - 스레드: " + Thread.currentThread().getName());
}
}
컨트롤러 작성 (호출부):
@RestController
public class ConcurrentController {
@Autowired
private ConcurrentService concurrentService;
@GetMapping("/concurrent")
public String executeConcurrentTasks() throws InterruptedException {
for (int i = 1; i <= 5; i++) {
concurrentService.processTask(i);
}
return "Concurrent Tasks Started";
}
}
실행 결과:
스레드가 교차하면서 여러 작업이 논리적으로 동시에 처리되는 것을 로그를 통해 확인할 수 있다.
✅ 병렬성(Parallelism) 예제 (병렬 스트림 사용)
실제 CPU 코어를 활용하여 병렬 처리가 이루어지는 모습을 확인한다.
서비스 클래스 작성:
@Service
public class ParallelService {
public int sumUsingParallelStream() {
return IntStream.rangeClosed(1, 1_000_000)
.parallel() // 병렬 스트림 사용
.sum();
}
}
컨트롤러 작성 (호출부):
@RestController
public class ParallelController {
@Autowired
private ParallelService parallelService;
@GetMapping("/parallel")
public String executeParallelTasks() {
long start = System.currentTimeMillis();
int sum = parallelService.sumUsingParallelStream();
long end = System.currentTimeMillis();
return "합계: " + sum + ", 소요 시간: " + (end - start) + "ms";
}
}
실행 결과:
멀티코어 CPU에서 작업이 동시에 진행되어, 단일 스트림 대비 빠르게 결과를 도출하는 것을 볼 수 있다.
📌 5. 사용 시 주의점 및 팁
- 동시성을 구현할 때 스레드의 개수가 너무 많으면 컨텍스트 스위칭 비용이 증가하여 오히려 성능이 떨어질 수 있으므로, 적절한 스레드 풀 크기를 설정해야 한다.
- 병렬 스트림은 데이터의 크기가 작거나 단순한 작업에서는 오히려 성능 저하를 유발할 수 있으므로, 충분히 복잡하거나 양이 많은 작업에서 사용하는 것이 적합하다.
📌 6. 마무리 및 요약
이 글에서는 다음의 내용을 다루었다.
- 동시성은 논리적으로 동시에 처리하는 방식으로, 응답성과 자원 활용을 높인다.
- 병렬성은 물리적으로 동시에 처리하는 방식으로, 처리 성능과 속도를 증가시킨다.
- Spring에서 @Async와 병렬 스트림을 통해 두 가지 개념을 간편하게 구현 가능하다.
반응형