Java Race Condition(경쟁 상태)

2SEONGA·2025년 1월 23일
0

Java

목록 보기
7/13

Race Condition(경쟁 상태)

여러 스레드가 동시에 공유 자원에 접근하여 예상치 못한 결과가 발생하는 상황


1) 함수 단위 Blocking : synchronized

메서드 전체에 synchronized 키워드를 사용하여, 한 번에 하나의 스레드만 해당 메서드에 접근할 수 있도록 보장

  • 장점
    : 간단한 동기화 구현
  • 단점
    : 메서드 전체를 동기화하기 때문에 성능 저하 발생 가능
public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // 생성자는 private으로 외부에서 호출 불가
    }

    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

설명
1. synchronized 키워드를 메서드에 사용하면 함수 전체가 하나의 락을 공유
2. 여러 스레드가 동시에 getInstance()를 호출하더라도, 락을 획득한 하나의 스레드만 객체를 생성하거나 반환


2) 변수 생성 단위 Blocking : volatile + synchronized

volatile, synchronized 키워드를 함께 사용하여, 객체 생성 시 더블-체크 잠금(Double-Checked Locking)을 구현

  • 장점
    : 객체가 이미 생성된 경우에는 락을 사용하지 않고 바로 반환 가능, 성능 개선
  • 단점
    : 코드 복잡도 약간 증가
public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {
        // 생성자는 private으로 외부에서 호출 불가
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) { // 블록 단위 동기화
                if (instance == null) {     // 두 번째 확인
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

설명
1. volatile 키워드는 가시성(Visibility)을 보장하여, 여러 스레드가 instance 변수의 최신 상태를 제공
2. 첫 번째 if (instance == null)에서 객체 생성 여부 확인
3. (Singleton.class) 블록 안에서 두 번째 확인을 통해 객체를 생성


Lazy Holder(권장되는 방식)

래스 로더의 초기화 단계에서 JVM이 보장하는 스레드 안전성을 이용
static 내부 클래스에 싱글턴 객체를 생성

  • 장점: 간결하고 성능도 우수하며, JVM이 기본적으로 스레드 안전성을 보장
public class Singleton {
    private Singleton() {
        // 생성자는 private으로 외부에서 호출 불가
    }

    private static class LazyHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return LazyHolder.INSTANCE;
    }
}

설명
1. 내부 정적 클래스 LazyHolderSingleton 객체를 생성하고, 클래스가 로드될 때 초기화
2. getInstance()를 호출할 때 LazyHolder가 처음으로 로드되며, 이 시점에 Singleton 객체 생성
3. JVM의 클래스 초기화 규칙에 따라, 클래스 초기화는 스레드 안전하게 수행


profile
(와.. 정말 Chill하다..)

0개의 댓글