>  기사  >  Java  >  싱글톤이 중단되지 않도록 하세요! Java에서 스레드로부터 안전하게 만드는 방법은 다음과 같습니다.

싱글톤이 중단되지 않도록 하세요! Java에서 스레드로부터 안전하게 만드는 방법은 다음과 같습니다.

Patricia Arquette
Patricia Arquette원래의
2024-11-02 09:55:02277검색

Don’t Let Your Singleton Break! Here’s How to Make It % Thread-Safe in Java

이 게시물에서는 즉시 초기화, 이중 확인 잠금 및 내부 정적 클래스 접근 방식이 있습니다. 또한 final 키워드가 싱글톤의 무결성을 보장하는 데 왜 유용한지 논의하겠습니다.

싱글톤을 사용하는 이유는 무엇입니까?

싱글톤은 애플리케이션 전체에서 클래스의

한 인스턴스가 정확히 필요할 때 유용합니다. 일반적인 사용 사례에는 로깅, 구성 또는 연결 풀과 같은 공유 리소스 관리가 포함됩니다. 싱글톤은 클래스에 액세스하기 위한 여러 요청이 새 클래스를 생성하는 대신 동일한 인스턴스를 공유하도록 보장합니다.

1. 즉시 초기화: 가장 간단한 싱글톤

열심히 초기화 패턴은 클래스가 로드될 때 싱글톤 인스턴스를 생성합니다. 이는 JVM이 클래스를 로드할 때 인스턴스가 생성되기 때문에 간단하고 스레드 안전성을 보장합니다.


public final class Singleton {
    // Instance is created at class loading time
    private static final Singleton INSTANCE = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
즉시 초기화의 장점과 단점

장점:

    JVM은 클래스 초기화가 스레드로부터 안전함을 보장하므로 기본적으로 간단하고 스레드로부터 안전합니다.
  • 동기화나 추가적인 복잡성이 필요하지 않습니다.

단점:

    인스턴스는 사용 여부에 관계없이 생성되므로 싱글톤이 전혀 필요하지 않으면 리소스 낭비가 발생할 수 있습니다.

사용 시기: 즉시 초기화는 싱글톤 클래스가 가볍고 애플리케이션 런타임 중에 사용될 것이 확실할 때 가장 좋습니다.


2. 이중 확인 잠금을 사용한 지연 초기화

필요할 때까지 싱글톤 생성을 지연하려는 경우(

지연 초기화라고도 함) 이중 확인 잠금이 스레드로부터 안전한 솔루션을 제공합니다. 최소한의 동기화를 사용하며 처음 액세스할 때만 인스턴스가 생성되도록 합니다.

public final class Singleton {  // Marked as final to prevent subclassing

    // volatile ensures visibility and prevents instruction reordering
    private static volatile Singleton instance;

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {               // First check (no locking)
            synchronized (Singleton.class) {   // Locking
                if (instance == null) {        // Second check (with locking)
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
이중 확인 잠금이 작동하는 이유

  1. 첫 번째 확인: 동기화된 블록 외부의 if(instance == null) 확인을 사용하면 getInstance()가 호출될 때마다 잠김을 방지할 수 있습니다. 이는 초기화 후 향후 호출에 대해 동기화된 블록을 우회하여 성능을 향상시킵니다.

  2. 동기화 블록: 인스턴스가 null이면 동기화 블록을 입력하면 단 하나의 스레드만 싱글톤 인스턴스를 생성하게 됩니다. 이 지점에 도달하는 다른 스레드는 경쟁 조건을 방지하기 위해 기다려야 합니다.

  3. 두 번째 확인: 동기화된 블록 내에서 인스턴스를 다시 확인하여 현재 스레드가 기다리는 동안 다른 스레드가 초기화하지 않았는지 확인합니다. 이렇게 다시 확인하면 싱글톤 인스턴스가 하나만 생성됩니다.

휘발성이 필요한 이유

휘발성 키워드는 명령어 재정렬을 방지하기 위해 이중 확인 잠금 패턴에 필수적입니다. 이것이 없으면 문은 인스턴스 = new Singleton(); 완전히 초기화되기 전에 다른 스레드에 완료된 것으로 나타나 부분적으로 구성된 인스턴스가 반환될 수 있습니다. 휘발성은 일단 인스턴스가 null이 아니면 완전히 구성되어 모든 스레드에 표시되도록 보장합니다.

Final이 모범 사례인 이유

여기서는 하위 클래스화를 방지하기 위해 마지막 키워드가 사용됩니다. 싱글톤 클래스를 최종으로 표시하면 두 가지 주요 이점이 있습니다.

  1. 하위 클래스화 방지: 클래스를 최종 클래스로 만들어 다른 클래스가 클래스를 확장하는 것을 방지합니다. 서브클래싱으로 인해 추가 인스턴스가 발생하여 싱글톤 패턴이 깨질 수 있으므로 이렇게 하면 싱글톤 클래스의 인스턴스가 하나만 존재할 수 있습니다.

  2. 불변성 신호: final은 싱글톤 클래스가 불변성을 갖도록 의도되었으며 확장되어서는 안 된다는 점을 다른 개발자에게 명확하게 표시하는 역할을 합니다. 이렇게 하면 코드를 더 쉽게 이해하고 유지 관리할 수 있습니다.

간단히 말해서 final은 싱글톤의 무결성을 강화하고 서브클래싱으로 인한 예상치 못한 동작을 방지하는 데 도움이 됩니다.

이중 확인 잠금의 장점과 단점

장점:

  • 지연 초기화는 필요할 때까지 생성을 지연시켜 리소스를 절약합니다.
  • 재확인으로 인한 동기화 오버헤드가 최소화됩니다.

단점:

  • 약간 더 복잡하며 안전을 위해 휘발성이 필요합니다.
  • 열심히 초기화하는 것으로 충분한 단순한 싱글톤 요구 사항에는 과잉일 수 있습니다.

사용 시기: 이 패턴은 싱글톤 클래스가 리소스 집약적이고 항상 필요하지 않을 수 있거나 다중 스레드 환경에서의 성능이 문제가 될 때 유용합니다.


3. 내부 정적 클래스: 더 깔끔한 지연 초기화 대안

지연 초기화에 대한 스레드로부터 안전한 대체 접근 방식은 내부 정적 클래스 패턴입니다. 이는 Java의 클래스 로딩 메커니즘을 활용하여 명시적인 동기화 없이 필요할 때만 싱글톤 인스턴스를 초기화합니다.

public final class Singleton {
    // Instance is created at class loading time
    private static final Singleton INSTANCE = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

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

내부 정적 클래스의 작동 방식

이 패턴에서 SingletonHelper 클래스는 getInstance()가 처음 호출될 때만 로드됩니다. 이는 INSTANCE의 초기화를 트리거하여 동기화된 블록 없이 지연 로딩을 보장합니다.

내부 정적 클래스의 장단점

장점:

  • 휘발성 또는 동기화된 블록이 필요 없이 스레드로부터 안전합니다.
  • 간단하고 깔끔하며 초기화가 지연되도록 설계되었습니다.

단점:

  • Java의 클래스 로딩 메커니즘에 익숙하지 않은 신규 개발자에게는 다소 덜 직관적입니다.

사용 시기: 깨끗하고 유지 관리 가능한 코드로 지연 초기화를 원할 때 내부 정적 클래스 패턴을 사용하세요. 이는 단순성과 스레드 안전성으로 인해 종종 선호되는 선택입니다.


마무리

Java에서 스레드로부터 안전한 싱글톤을 구현하는 세 가지 인기 있는 방법을 살펴보았습니다.

  1. 즉시 초기화: 싱글톤이 가볍고 항상 사용되는 간단한 경우에 가장 적합합니다.
  2. 이중 확인 잠금: 지연 초기화가 필요한 성능에 민감한 멀티스레드 환경에 적합합니다.
  3. 내부 정적 클래스: Java의 클래스 로딩 동작을 사용하여 지연 초기화에 대한 깔끔하고 스레드로부터 안전한 접근 방식입니다.

각 접근 방식에는 장점이 있으며 다양한 시나리오에 적합합니다. 자신의 프로젝트에서 시도해 보고 어느 것이 가장 적합한지 확인하세요! 선호하는 접근 방식이나 궁금한 점이 있으면 댓글로 알려주세요.

즐거운 코딩하세요! ?‍??‍?

위 내용은 싱글톤이 중단되지 않도록 하세요! Java에서 스레드로부터 안전하게 만드는 방법은 다음과 같습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.