프로그래밍Java 중급/백엔드 개발자

자바에서 스레드 작업에 대해 아는 것과 스레드 안전성을 어떻게 조직하는지에 대한 설명

Hintsage AI 어시스턴트로 면접 통과

답변.

자바에서 스레드 작업은 Thread, Runnable 클래스 및 java.util.concurrent 패키지를 통해 구현됩니다. 스레드 안전성을 조직하기 위해 다양한 동기화 메커니즘이 사용됩니다:

  • 동기화된 블록/메서드 (synchronized)는 여러 스레드가 경쟁 없이 공통 데이터에 접근할 수 있도록 허용합니다.
  • volatile은 스레드 간 변수 변경 상황을 보장합니다.
  • java.util.concurrent의 클래스들 (예: ReentrantLock, Semaphore, AtomicInteger, ConcurrentHashMap)은 보다 유연한 동기화 방법을 제공합니다.

동기화 예:

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

원자 클래스 사용 예:

import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }

속임수 질문.

volatile 키워드가 int 유형의 카운터를 증가시킬 때 스레드 안전성을 보장합니까?

답변: 아닙니다. volatile은 스레드 간에 값의 가시성만을 보장하고, 연산의 원자성을 보장하지 않습니다. 증가 연산은 원자적이지 않은 작업이며 (count++는 읽기, 증가, 쓰기를 포함합니다) 데이터 손실의 가능성이 있습니다. 스레드 안전한 증가에 대해서는 동기화 또는 AtomicInteger와 같은 클래스를 사용해야 합니다.

volatile int count = 0; // count++는 스레드 안전하지 않음!

주제에 대한 이해 부족으로 인한 실제 오류 사례.


이야기

온라인 상점에서 보너스 계좌는 volatile 카운터를 통해 업데이트되었습니다. 수천 명의 사용자가 주문을 처리하는 동안 스레드 경쟁으로 인해 일부 보너스가 손실되었습니다.


이야기

직원이 다중 스레드 애플리케이션에서 생산자와 소비자 간의 공유 버퍼로 일반 ArrayList를 사용하여 ConcurrentModificationException이 발생했습니다. 해결책은 동기화 블록을 사용하거나 CopyOnWriteArrayList로 교체하는 것이었습니다.


이야기

결제 처리에서 개발자는 두 가지 관련이 없는 메서드를 사용하여 "금액 확인 및 차감" 작업을 수행했습니다. 높은 부하 상황에서는 원자적 거래 및 잠금을 구현하기 전까지 이로 인해 이중 청구가 발생했습니다.