synchronized, volatile에 대해서

synchronized, volatile에 대해서

생성일
Oct 26, 2024 04:38 PM
최종 편집 일시
Last updated October 26, 2024
태그
JAVA
synchronized와 volatile은 자바에서 멀티스레드 환경에서 데이터 일관성과 동시성을 관리하기 위한 키워드이다.
쓰레드 간의 데이터 공유 방식과 동기화를 관리하는 데 주로 사용된다.

1. synchronized

synchronized는 자바에서 메서드나 블록에 사용하여 동시 접근을 제한하는 역할을 한다.
이를 통해 한 번에 하나의 쓰레드만 특정 코드에 접근하도록 보장하므로 동시성 문제를 해결하는 데 유용하다.

특징

  • 공기화된 메서드 또는 블록은 한 번에 하나의 쓰레드만 접근할 수 있다.
  • 특정 코드가 임계 구역(critical section)이 되어 여러 쓰레드가 동시에 접근하면 안 되는 경우에 사용한다.
  • 메서드나 블록 앞에 synchronized 키워드를 붙이면, JVM이 내부적으로 모니터 락을 걸어 동기화를 관리한다.
public class Counter { private int count = 0; public synchronized void increment() { // synchronized 메서드 count++; } public int getCount() { return count; } }
increment 메서는 동기화되어 여러 쓰레드가 동시에 호출해도 한 번에 한 쓰레드만 접근할 수 있게 된다.
 
블록으로 사용
public void increment() { synchronized (this) { // synchronized 블록 count++; } }

2. volatile

변수의 값을 모든 쓰레드에서 즉시 읽고 쓰게 보장하는 역할을 한다.
자바에서는 쓰레드가 변수를 캐시하여 사용하기 때문에, 변수의 최신 값이 모든 쓰레드에 즉시 반영되지 않을 수 있다.
이 때 volatile을 사용하면 각 쓰레드가 메인 메모리에서 항상 최신 값을 읽어오도록 보장한다.

특징

  • 변수 앞에만 사용 가능하다. 메서드나 블록에는 사용할 수 없다.
  • 동기화 없이 최신 값을 보장하지만, 원자성을 보장하지 않는다. 따라서 i++같은 연산에서는 여전히 동기화를 추가해야 한다.
    • i++ 같은 증감 연산은 원자적이지 않기 때문에 동기화가 필요한 경우가 있다.
    • 이 연산은 읽기, 연산, 쓰기의 세 단계로 이루어진다.
    • 읽기: 현재 메모리에서 i 값을 읽어온다.
    • 연산: i의 값에 1을 더한다.
    • 쓰기: 연산 결과를 다시 메모리에 저장한다.
    • 이 세 단계는 별개로 수행되기 때문에 여러 쓰레드가 동시에 i++를 실행하면 동시성 문제가 발생할 수 있게 된다.
    • 이럴 때는 i++ 대신 AtomicInteger 같은 AtomicType을 사용하는 것이 좋다.
  • 간단한 읽기와 쓰기 연산에서 쓰레드 간 최신 상태를 보장하는 데 사용한다.
public class Flag { private volatile boolean flag = false; public void setFlagTrue() { flag = true; } public boolean isFlagTrue() { return flag; } }
위처럼 flag를 volatile로 선언하면 flag 값을 변경할 때 모든 쓰레드에 즉시 최신 값이 반영된다.

Synchronized, volatile 비교

synchronized
volatile
용도
임계 구역 관리로 동기화
변수의 최신 값을 보장
보장 성질
원자성, 가시성
가시성
사용 대상
메서드, 코드 블록
변수
성능
상대적으로 느림(락 때문)
상대적으로 빠름
동시성 문제 해결
주로 복잡한 동기화 문제 해결에 유용
단순한 플래그 변경 등의 문제 해결에 적합

사용 예시

  • synchronized는 공유 리소스(리스트, 맵 등)나 복잡한 연산이 동반되는 메서드에서 동기화가 필요할 때 주로 사용된다.
  • volatile은 플래그나 간단한 카운터와 같이 읽기와 쓰기 연산만 필요한 상황에서 최신 상태를 보장할 때 유용하다.