ConcurrencyThread실시간

스레드와 동시성

여러 작업을 동시에 처리할 때 발생하는 문제와 해결 방법을 직접 체험합니다.

왜 알아야 하나요?

월요일 아침, 급하게 호출이 왔습니다

"결제 금액이 이상해요. 10,000원 상품인데 어떤 고객은 0원으로 결제됐대요!"

로그를 확인해보니...

두 명이 동시에 같은 쿠폰을 사용했고, 둘 다 100% 할인이 적용됐습니다.

이것이 바로 Race Condition!

동시성을 이해하면 이런 버그를 예방할 수 있습니다.

한눈에 보기

Race Condition

여러 스레드가 동시에 같은 데이터를 수정하면 결과가 꼬입니다.

예: 재고 1개인데 2명이 동시 구매 → 재고 -1

Deadlock

두 스레드가 서로의 자원을 기다리며 영원히 멈춥니다.

예: A가 B를 기다리고, B가 A를 기다림

Thread Pool

스레드를 미리 만들어두고 재사용해서 효율적으로 관리합니다.

예: 요청마다 스레드 생성 → 메모리 폭발

핵심 개념

스레드(Thread)란?

프로그램 안에서 독립적으로 실행되는 작업 흐름입니다. 한 프로그램이 여러 일을 동시에 하려면 스레드가 여러 개 필요해요.

쉬운 비유: 식당의 종업원
  • 종업원 1명 = 한 번에 한 테이블만 서빙
  • 종업원 4명 = 동시에 4 테이블 서빙 가능
  • 하지만! 같은 주문서를 동시에 수정하면 문제 발생
동기화(Synchronization)란?

여러 스레드가 순서대로 자원에 접근하도록 제어하는 것입니다. "한 번에 한 명씩만!" 규칙을 만드는 거예요.

동기화 도구들:
  • synchronized: 가장 기본적인 락
  • AtomicInteger: 숫자 연산을 원자적으로
  • ReentrantLock: 더 세밀한 제어 가능

실무에서는

이렇게 하면 망해요
new Thread().start() 남발

→ 스레드 수천 개 → 메모리 폭발

공유 변수를 synchronized 없이 수정

→ 데이터 손실, 버그 재현 어려움

락 범위를 너무 넓게 설정

→ 병렬 처리 효과 없음, 느려짐

이렇게 하세요
ExecutorService 사용

→ 스레드 재사용, 안정적 관리

AtomicInteger로 카운터 관리

→ 락 없이도 안전한 증감

락 순서 통일로 데드락 예방

→ 항상 A → B 순서로 락 획득

직접 체험하기

각 탭을 선택해서 동시성 문제를 직접 발생시키고 해결해보세요.

상황: 마지막 1개 남은 한정판 운동화

온라인 쇼핑몰에 한정판 운동화가 딱 1개 남았어요. 그런데 두 명이 동시에 구매 버튼을 눌렀어요!

민수: "재고 1개네! 구매!"
영희: "재고 1개네! 구매!"

결과: 둘 다 구매 성공? 재고가 -1개가 되어버렸어요!

실험 설정
동시 구매자 수 (스레드)2
각자 구매 시도 횟수1000
재고 카운터 상황
👤
스레드 1
카운터0
👤
스레드 2
핵심 교훈

Race Condition: 여러 스레드가 동시에 같은 데이터를 수정하면 발생

해결책: synchronized, AtomicInteger, Lock 등으로 한 번에 한 명씩 처리

은행 ATM도 마찬가지! 잔액 조회 → 출금 사이에 다른 거래가 끼어들면 안 돼요.

더 알아보기

다음 단계

  • • Connection Pool - DB 연결 관리
  • • Caching - Redis 캐시 전략
  • • Message Queue - 비동기 처리

참고 자료

  • • Java Concurrency in Practice (책)
  • • jconsole, VisualVM (모니터링 도구)
  • • Thread Dump 분석 방법