경쟁 μƒνƒœ ( Race Condition ) 🏍

LzhtkΒ·2025λ…„ 8μ›” 16일

μ˜€λŠ˜μ€ λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ λ°œμƒν•˜λŠ” λŒ€ν‘œμ μΈ 문제 쀑 ν•˜λ‚˜μΈ 경쟁 μƒνƒœμ— λŒ€ν•΄ μ•Œμ•„λ³΄μž ❗


1 . πŸ€Όβ€β™‚οΈ 경쟁 μƒνƒœλž€ ? ( Race Condition )

  • λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œλŠ” μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— 같은 μžμ› ( λ©”λͺ¨λ¦¬, 파일 , DB λ“± )에 μ ‘κ·Όν•  수 μžˆλ‹€.
  • μ΄λ•Œ μ‹€ν–‰ μˆœμ„œμ— 따라 κ²°κ³Όκ°€ λ‹¬λΌμ§€λŠ” 상황을 경쟁 μƒνƒœ ( Race Condition )라고 λΆ€λ₯Έλ‹€.
  • 즉 ❗ λˆ„κ°€ λ¨Όμ € 싀행됐냐에 따라 ν”„λ‘œκ·Έλž¨ κ²°κ³Όκ°€ λ‹¬λΌμ§ˆ 수 μžˆλŠ” 예츑 λΆˆν—ˆμ˜ μƒνƒœμΈ 것이닀.
  • μ΄λŠ” ν”„λ‘œκ·Έλž¨μ˜ μ•ˆμ •μ„±κ³Ό 일관성을 κΉ¨λœ¨λ¦¬λŠ” λŒ€ν‘œμ μΈ λ©€ν‹°μŠ€λ ˆλ“œ λ¬Έμ œμ΄λ‹€.

2 . πŸ€·β€β™€οΈ 경쟁 μƒνƒœκ°€ λ°œμƒν•˜λŠ” 원인은 ?

  • κ³΅μœ μžμ› : μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— 읽고 μ“°κΈ°λ₯Ό μˆ˜ν–‰ν•  경우 μƒνƒœ λΆˆμΌμΉ˜κ°€ λ°œμƒν•  수 μžˆλ‹€.
  • λΉ„μ›μžμ  μ—°μ‚° : x = x + 1κ³Ό 같은 λ‹¨μˆœ 연산도 사싀은 읽기 -> 계산 -> μ“°κΈ°λΌλŠ” 3단계λ₯Ό κ±°μ³μ„œ λ‚˜λ‰˜μ–΄ μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμ΄λ‹€.
  • μŠ€μΌ€μ€„λŸ¬μ˜ λΆˆν™•μ‹€μ„± : μ–΄λ–€ μŠ€λ ˆλ“œκ°€ μ–Έμ œ CPUλ₯Ό μ μœ ν• μ§€ 예츑 λΆˆκ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.
  • μ μ ˆν•œ λ™κΈ°ν™”μ˜ λΆ€μž¬ : Lock, Mutex, Semaphore 같은 동기화 μž₯μΉ˜κ°€ μ—†κ±°λ‚˜ 잘λͺ» μ‚¬μš©λœ 경우

3 . πŸ‘©πŸ»β€πŸ« λŒ€ν‘œμ μΈ EX

  • μ€ν–‰μ˜ κ³„μ’Œ μž…μΆœκΈˆ 문제

    • 두 μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— κ³„μ’Œμ˜ μž”μ•‘μ„ μˆ˜μ •ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

public void withdraw(int amount) {
	if (balance >= amount) {
   		balance = balance - amount; 
    }
}  
  • μŠ€λ ˆλ“œ Aκ°€ balance >= amount 검사 ν›„, 아직 balanceλ₯Ό κ°±μ‹ ν•˜κΈ° 전에
    μŠ€λ ˆλ“œ B도 같은 검사λ₯Ό 톡과 -> λ‘˜λ‹€ 같은 μΆœκΈˆμ„ μ§„ν–‰
  • 결과적으둜 μž”μ•‘μ΄ μŒμˆ˜κ°€ λ˜κ±°λ‚˜ μ‹€μ œλ³΄λ‹€ 많이 λΉ μ Έλ‚˜κ°€λŠ” λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.

4 . πŸ§™β€β™‚ 경쟁 μƒνƒœ ν•΄κ²° μ „λž΅

4 - 1 . 동기화 ( Synchronization )

  • Lock / Synchroized 블둝
    • ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œ 곡유 μžμ›μ— μ ‘κ·Όν•˜λ„λ‘ μ œν•œ
    • EX
public synchronized void withdraw(int amount) {
	if (balance >= amount) {
    	balance = balance - amount;
    }
}
  • ReentrantLock ( λͺ…μ‹œμ  Lock μ œμ–΄ )
    • 더 μ„Έλ°€ν•œ Lock μ œμ–΄ κ°€λŠ₯ ( νƒ€μž„μ•„μ›ƒ, 쑰건 λŒ€κΈ° λ“± 지원 )

4 - 2 . μ›μžμ  μ—°μ‚°

  • AtomicInteger, AtomicLong 같은 μ›μžμ  클래슀 μ‚¬μš©
  • λ‚΄λΆ€μ μœΌλ‘œ CAS(Compare-And-Swap) μ•Œκ³ λ¦¬μ¦˜μ„ 톡해 동기화 문제λ₯Ό ν•΄κ²°
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();

4 - 3 . λΆˆλ³€ 객체 ν™œμš©

  • λ³€κ²½ κ°€λŠ₯ν•œ μƒνƒœλ₯Ό κ³΅μœ ν•˜μ§€ μ•Šκ³ , μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜λŠ” 방식
  • ex : String ν΄λž˜μŠ€λŠ” λΆˆλ³€ κ°μ²΄μ΄λ―€λ‘œ μŠ€λ ˆλ“œ Safeβœ…

4 - 4 . μŠ€λ ˆλ“œ 둜컬 λ³€μˆ˜

  • 각 μŠ€λ ˆλ“œλ§ˆλ‹€ 독립적인 λ³€μˆ˜λ₯Ό μœ μ§€ν•˜μ—¬ 곡유 자체λ₯Ό 피함
  • Ex : ThreadLocal μ‚¬μš©

4 - 5 . 병행 μ œμ–΄( Concurrency Control) 기법

  • μ„Έλ§ˆν¬μ–΄(Semaphore) : λ™μ‹œμ— μ ‘κ·Ό κ°€λŠ₯ν•œ μŠ€λ ˆλ“œ 수λ₯Ό μ œν•œ
  • ReadWriteLock : 읽기 μŠ€λ ˆλ“œλŠ” λ™μ‹œ ν—ˆμš©, μ“°κΈ° μŠ€λ ˆλ“œλŠ” 단독 ν—ˆμš©
  • λ°μ΄ν„°λ² μ΄μŠ€ νŠΈλžœμž­μ…˜ : DBμ°¨μ›μ—μ„œ λ™μ‹œμ„± μ œμ–΄ ( ACID 보μž₯ )

4 - 6 . Concurrent μ»¬λ ‰μ…˜

  • ConcurrentHashMap, CopyOnWriteArrayList 등은 λ‚΄λΆ€μ μœΌλ‘œ λ™μ‹œμ„± μ œμ–΄κ°€ 적용된 μ»¬λ ‰μ…˜
  • 직접 synchronizedλ₯Ό κ±Έμ§€ μ•Šμ•„λ„ μ•ˆμ „ν•œ 병렬 μ ‘κ·Ό κ°€λŠ₯

πŸ”š 마무리

경쟁 μƒνƒœλŠ” λ©€ν‹°μŠ€λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ ν”Όν•  수 μ—†λŠ” κ³Όμ œμ΄λ‹€ ❕
λͺ¨λ“  상황에 ν•˜λ‚˜μ˜ 정닡은 μ—†μœΌλ©°, 곡유 μžμ›μ˜ νŠΉμ„±κ³Ό μ“°κΈ° λΉˆλ„, μ„±λŠ₯ μš”κ΅¬μ‚¬ν•­μ— 따라
μ μ ˆν•œ 동기화 μ „λž΅μ„ μ„ νƒν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€. πŸ€—
였늘 μ•Œμ•„λ³Έ 것을 ν† λŒ€λ‘œ 문제 상황에 λ§žλŠ” 동기화 μ „λž΅μ„ μ„ νƒν•˜κ³ , λΆˆν•„μš”ν•œ λ™κΈ°ν™”λŠ” ν”Όν•˜λ©΄μ„œ 이λ₯Ό μΆ©λΆ„νžˆ μ œμ–΄ν•΄λ³΄μž. πŸ’―

0개의 λŒ“κΈ€