[Java] synchronized

gyeol·2025년 10월 16일

자바

목록 보기
22/24
post-thumbnail

synchronized

synchronized는 자바에서 가장 기본적인 동기화 키워드로, 한 번에 하나의 스레드만 특정 블록에 접근하도록 락을 걸어주는 기능이다.

  • 사용 간단
  • 자동으로 락 획득/해제 가능
  • 세밀한 락 제어나 타임아웃 설정은 불가능
  • synchronized는 JVM 수준에서 락을 관리하는 동기화 메커니즘
  • 객체 또는 클래스 단위로 모니터 락을 획득해 동기화
  • 내부적으로 JVM의 모니터와 운영체제의 뮤텍스 락을 활용함

왜 사용하는가?

JVM에서 여러 스레드는 공유 자원을 Heap 영역에 저장해 함께 접근한다. 하지만 각 스레드는 독립적인 Thread Stack과 CPU 레벨의 캐시 메모리를 사용한다. 즉, 한 스레드가 Heap에 있는 값을 수정해도 다른 스레드의 CPU 캐시에 이전 값이 남아있을 수 있다. 이것이 바로 가시성(visibility) 문제가 된다.

synchronized의 핵심 역할설명
Mutual Exclusion (상호 배제)한 시점에 오직 하나의 스레드만 특정 블록/메서드에 접근 가능
Visibility (가시성 보장)스레드가 락(lock)을 획득하거나 해제할 때, CPU 캐시 ↔ 메인 메모리(RAM) 동기화 발생

내부 원리

  • 스레드가 synchronized 블록에 들어갈 때

    • JVM이 모니터 락 획득
    • CPU 캐시에 있던 데이터를 RAM으로 flush해서 최신 상태로 만듦
  • 실행 중에는

    • 다른 스레드는 같은 블록에 접근할 수 없고 대기상태가 됨
  • 블록이 끝날 때

    • 변경된 값을 다시 RAM으로 반영하고 락을 해제해 다른 스레드가 들어올 수 있도록 함

JVM에서 synchronized가 동작하는 원리

synchronized 키워드를 만나면 JVM이 객체의 모니터를 활용해 락을 관리한다.

  • 락 획득 (monitorenter)

    • 스레드가 진입 시 객체의 모니터 락 획득
    • 이미 다른 스레드가 락을 가지고 있다면 대기(BLOCKED) 상태로 전환
  • 임계 구역 실행

    • 락을 얻은 스레드만 코드 블록을 실행할 수 있음
    • 실행 중에는 다른 스레드가 접근할 수 없음
  • 락 해제 (monitorexit)

    • synchronized 블록이 끝나면 JVM이 락 해제
    • 이 시점에 CPU 캐시의 변경 내용이 RAM으로 flush 되어 다른 스레드가 최신 데이터를 볼 수 있게 됨

뮤텍스와 세마포어

멀티스레드 환경에서 공유 자원에 대한 접근을 제어하는 대표적인 두 가지 기법이다.

뮤텍스 (Mutex)

뮤텍스는 한 번에 오직 하나의 스레드만 공유 자원에 접근할 수 있도록 제한하는 락이다. 한 스레드가 락을 획득하면 다음 스레드는 무조건 대기해야 한다.

  1. Thread A가 락을 획득하고 자원 사용
  2. 다른 Thread B가 접근하려면 락이 해제될 때까지 대기
  3. Thread A가 자원 사용을 끝내면 락 해제
  4. Thread B가 락을 획득하고 자원 사용

세마포어 (Semaphore)

세마포어는 허용 가능한 스레드 개수를 지정할 수 있는 락이다. 운영체제와 Java Semaphore에서 많이 사용된다.

  1. 초기 카운터 값이 n이라면 동시에 최대 n개의 스레드 접근 가능
  2. 새로운 스레드가 접근하면 카운터 값 감소
  3. 스레드가 끝나면 카운터 증가
  4. 카운터가 0이 되면 새로은 스레드는 대기 상태 (0이면 대기, 1 이상이면 접근 가능)
profile
공부 기록 공간 '◡'

0개의 댓글