>  기사  >  Java  >  동시성 싱글톤 모드에 대한 자세한 소개(코드 포함)

동시성 싱글톤 모드에 대한 자세한 소개(코드 포함)

不言
不言앞으로
2019-04-13 11:59:252600검색

이 글은 동시성(코드 포함)의 싱글톤 모드에 대해 자세히 소개합니다. 필요한 친구들이 참고할 수 있기를 바랍니다.

가장 많은 메모리를 소비하는 객체 생성 프로세스를 제한해야 합니다. 싱글톤 모드(Singleton)는 애플리케이션에서 특정 인스턴스의 인스턴스를 항상 하나만 유지하므로 프로그램 성능을 크게 향상시킬 수 있습니다.

다음에서는 싱글톤의 네 가지 구현 방법에 대해 설명합니다.
 单线程下的Singleton的稳定性是极好的,可分为两大类:

1. Eager(eager 유형): 클래스가 로드되는 즉시 객체를 생성합니다.

public class EagerSingleton {
    //1. 类加载时就立即产生实例对象,通过设置静态变量被外界获取
    //2. 并使用private保证封装安全性
    private static EagerSingleton eagerSingleton  = new EagerSingleton();
    
    //3. 通过构造方法的私有化,不允许外部直接创建对象,确保单例的安全性
    private EagerSingleton(){
    }
    public static EagerSingleton getEagerSingleton(){
        return eagerSingleton;
    }

2. Lazy(lazy 유형): 클래스가 로드될 때 개체가 즉시 생성되지 않으며 첫 번째 사용자가 개체를 얻을 때까지 인스턴스화되지 않습니다.

public class LazySingleton {
    //1. 类加载时并没有创建唯一实例
    private static LazySingleton lazySingleton;
    
    private LazySingleton() {
    }
        
    //2、提供一个获取实例的静态方法
    public static LazySingleton getLazySingleton() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        } 
        return lazySingleton;
    }

성능 측면에서 보면 LazySingleton이 EagerSingleton보다 확실히 더 좋습니다. 클래스를 로드하는 데 많은 리소스가 필요한 경우(예: 대용량 파일 정보 읽기) LazySingleton의 장점은 분명합니다. 하지만 코드를 읽어보면 치명적인 문제를 쉽게 발견할 수 있습니다. 여러 스레드 간에 보안을 유지하는 방법은 무엇입니까?

멀티 스레드 동시성 문제는 아래에서 분석됩니다.

이 문제를 해결하는 열쇠는 두 가지 측면에 있습니다. 1. 동기화 2. 성능

1. : 동기화 예외는 왜 발생하나요? 설명으로 전형적인 예를 들어보겠습니다.
스레드 A가 있고 스레드 B가 인스턴스를 얻기 위해 동시에 getLazySingleton()을 호출하면 A가 이를 준비할 때 인스턴스가 null이라고 판단합니다. 초기화 중 갑자기 A 스레드가 일시 중단되었습니다. 이때 개체 인스턴스화에 실패했으며 다음으로 더 나쁜 일이 발생했습니다. 스레드 B도 이때 인스턴스가 null이라고 판단했습니다. 인스턴스화 단계에서는 두 개의 인스턴스가 생성되어 원칙적으로 싱글톤이 파괴됩니다.

구출 방법?
Java 개발자라면 synchronized에 익숙할 텐데요. 멀티스레딩하면 대부분의 사람들이 그를 떠올립니다(JDK6 이후에는 성능이 엄청나게 향상되었으며 단순 동시성 문제를 해결하는 데 매우 적합합니다).

그럼 동기화를 사용하여 해결해 보겠습니다.

//由synchronized进行同步加锁
public synchronized static LazySingleton getLazySingleton() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        } 
        return lazySingleton;
    }

동기화 문제는 해결된 것 같지만 개발자로서 가장 중요한 것은 성능 보장입니다. 잠금 작업에 대한 코드 세그먼트는 비관적으로 잠겨 있으며 하나의 요청이 완료된 후에만 다음 요청을 실행할 수 있습니다. 일반적으로 동기화된 키워드가 포함된 코드 조각은 동일한 규모의 코드보다 몇 배 느릴 수 있는데, 이는 우리가 보고 싶지 않은 것입니다. 그렇다면 이 문제를 피하는 방법은 무엇입니까? Java의 동기화 정의에는 다음 제안이 있습니다. 나중에 동기화를 사용할수록 성능이 향상됩니다(세련된 잠금).

###### 2. 따라서 성능 문제 해결을 시작해야 합니다. 동기화에 따라 최적화: ######

public class DoubleCheckLockSingleton {
    //使用volatile保证每次取值不是从缓存中取,而是从真正对应的内存地址中取.(下文解释)
    private static volatile DoubleCheckLockSingleton doubleCheckLockSingleton;
    
    private DoubleCheckLockSingleton(){
        
    }
    
    public static DoubleCheckLockSingleton getDoubleCheckLockSingleton(){
        //配置双重检查锁(下文解释)
        if(doubleCheckLockSingleton == null){
            synchronized (DoubleCheckLockSingleton.class) {
                if(doubleCheckLockSingleton == null){
                    doubleCheckLockSingleton = new DoubleCheckLockSingleton();
                }
            }
        }
        return doubleCheckLockSingleton;
    }
}

위의 소스 코드는 고전적인 휘발성 키워드(JDK1.5 이후 재탄생) + 이중 검사 잠금(DoubleCheck)으로, 동기화로 인해 발생하는 성능 오버헤드를 최적화합니다. 최대 규모. Volatile과 DoubleCheck에 대해서는 아래에서 설명하겠습니다.

1.휘발성

은 JDK1.5 이후에 공식적으로 구현되어 사용되었습니다. 이전 버전에서는 특별한 구현 없이 이 키워드만 정의했습니다. 휘발성을 이해하려면 JVM 자체 메모리 관리에 대해 어느 정도 이해해야 합니다.

1.1 무어의 법칙에 따르면 메모리의 읽기 및 쓰기 속도는 CPU를 만족시키지 못하기 때문에 현대 컴퓨터에서는 이 방법을 도입했습니다. CPU에 캐시를 추가하는 메커니즘은 캐시에서 메모리 값을 미리 읽고 이를 캐시에 임시 저장한 후 메모리의 해당 값을 업데이트합니다.

**1.2** JVM은 PC의 접근 방식을 모방하여 자체 **작업 메모리**를 메모리에 분할합니다. 이 부분은 캐시와 동일하게 기능하므로 JVM 작업 효율성이 크게 향상됩니다. 이 접근 방식은 작업 메모리가 다른 메모리와 통신할 때 전송 문제도 발생합니다. 휘발성의 한 가지 기능은 캐시와 메모리 간의 불일치를 피하기 위해 메모리에서 최신 값을 강제로 읽는 것입니다.

1.3 휘발성의 또 다른 기능은 JVM과도 관련이 있습니다. 즉, JVM은 자체 판단을 사용하여 소스 코드의 실행 순서를 재정렬하여 명령 파이프라인의 연속성을 보장하여 최적의 결과를 얻습니다. 실행 계획. 이 접근 방식은 성능을 향상시키지만 DoubleCheck에 예상치 못한 결과가 발생하고 두 스레드가 서로 간섭할 수 있습니다. Volatile은 발생 전 보장(쓰기가 읽기보다 우선)을 제공하므로 개체가 방해받지 않고 안전과 안정성을 보장합니다.

2.DoubleCheck

이것은 현대 프로그래밍의 유산입니다. 동기화된 블록에 들어간 후 객체가 인스턴스화되었으며 다시 판단이 필요하다고 가정합니다.

물론 공식적으로 권장되는 싱글톤 구현 방법도 있습니다.

클래스 구성이 정의에서 이미 원자적이므로 위에서 언급한 문제는 다시 발생하지 않으며 좋은 싱글톤 방법입니다. 구현, 권장됩니다.

아아아아

위 내용은 동시성 싱글톤 모드에 대한 자세한 소개(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제