>Java >java지도 시간 >Java 싱글톤 패턴의 스레드 안전 문제를 해결하는 방법은 무엇입니까?

Java 싱글톤 패턴의 스레드 안전 문제를 해결하는 방법은 무엇입니까?

王林
王林앞으로
2023-05-09 19:28:061507검색

    1. 멀티스레딩 사용 시 고려해야 할 요소

    효율성 향상: 멀티스레딩을 사용하는 것은 CPU 자원을 최대한 활용하고 작업 효율성을 향상시키기 위한 것입니다.
    스레드 안전성: 가장 기본적인 것은 멀티스레딩 사용은 보안 스레드 안전 문제

    그래서 우리는 멀티스레딩 코드를 설계할 때 스레드 안전을 보장하면서 작업 실행의 효율성을 최대한 향상시켜야 합니다
    그래서:
    Fine-grained locking: 코드 잠금이 적고, 다른 코드가 동시에 실행될 수 있도록

    스레드 안전성 고려:

    공유 변수를 작동하지 않는 코드는 보안 문제가 없습니다.
    공유 변수를 읽으려면 휘발성을 사용하여 변수를 수정하세요.
    공유 변수를 작성하려면 동기화된 코드를 사용하세요 잠금

    2. 싱글턴 모드

    싱글턴 모드는 여러 인스턴스를 만들지 않고도 프로그램에 특정 클래스의 인스턴스가 하나만 있도록 보장할 수 있습니다. 예: DataSource(데이터 연결 풀), a 데이터베이스에는 하나만 필요합니다. 연결 풀 개체

    싱글턴 모드는 Hungry 모드와 게으른 모드로 구분됩니다

    1. Hungry 모드

    Hungry 모드는 클래스가 로드될 때 인스턴스를 생성합니다.

    이 방법은 스레딩 안전을 충족합니다(JVM은 내부적으로 잠금을 사용합니다. , 여러 스레드가 정적 메서드를 호출하면 하나의 스레드만 잠금을 위해 경쟁하고 생성을 완료하며 한 번만 실행됩니다. 클래스가 로드되었지만 처음 사용 시 생성됩니다.

    구현 코드:

    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton(){
     
        }
        public static Singleton getInstance(){
            return instance;
        }
    }

    위 코드를 보면 단일 스레드에서는 스레드 안전성 문제가 없지만 멀티 스레드 환경에서는 안전성이 있습니다. 문제?

    분석:

    인스턴스가 생성되지 않은 경우 여러 스레드가 getInstance 메소드를 호출하면 여러 스레드가 생성될 수 있으며 스레드 안전성 문제가 있습니다.
    그러나 일단 인스턴스가 생성되면 후속 스레드가 getInstance를 호출합니다. 메서드에는 스레드 안전 문제가 없습니다

    결과:
    인스턴스가 처음 생성될 때 스레드 안전 문제가 발생합니다

    3. 지연 모드(동기화를 사용하여 개선됨)

    동기화된 수정을 사용합니다????‍? ???️코드는 다음과 같습니다:

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

    이러한 방식으로 스레드 안전성을 구현하는 데 문제점은 무엇입니까?

    분석:

    우리는 메소드에 동기화된 수정을 사용합니다. 즉, 메소드가 호출될 때마다 잠금이 완료되지만 인스턴스는 한 번만 생성하면 됩니다. 즉, 인스턴스가 생성된 후에 잠금 해제 잠금

    결과:
    스레드에 안전하지만 비효율적입니다

    4. 지연 모드(이중 확인 잠금을 사용하여 개선됨)
    에 따라 변경합니다. 위 코드:

    결정된 경우 double을 사용하고 경쟁 잠금 빈도를 줄입니다. 인스턴스를 수정하려면 휘발성을 사용합니다.

    구현 코드:

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

    double if의 구문 분석:


    외부 if 판단:

    인스턴스는 다음과 같습니다. 인스턴스가 생성되면 한 번만 생성됩니다. 후속 작업이 필요하지 않으면 직접 반환하십시오.

    내부 if 판단: 인스턴스가 생성되지 않으면 여러 스레드가 동시에 잠금을 위해 경쟁합니다. 스레드는 성공적으로 경쟁하여 인스턴스를 생성하고 경쟁에 실패한 다른 스레드는 차단되고 대기하게 됩니다. 첫 번째 스레드가 잠금을 해제하면 실패한 스레드는 계속 경쟁하지만 인스턴스가 생성되었으므로 다음 작업을 수행해야 합니다. 다시 판단하면

    아래와 같이 분석을 그립니다.


    3. 휘발성 원칙

    휘발성은 Java 수준에서 가시성과 질서를 보장합니다. 다중 스레드는 휘발성을 읽을 수 있습니다. 변수를 동시에 수정하고 병렬로 실행합니다. 이는 잠금 없는 실행만큼 효율적입니다.

    휘발성 수정 변수 중에서 CPU는 캐시 일관성 프로토콜을 사용하여 최신 기본 메모리 데이터를 읽습니다.

    Java 싱글톤 패턴의 스레드 안전 문제를 해결하는 방법은 무엇입니까?캐시 일관성: 다른 스레드가 휘발성 수정 변수를 수정하면 CPU 캐시의 변수가 재설정됩니다. 유효하지 않은 경우 이 변수를 작동하려면 메인 메모리에서 해당 변수를 다시 읽어야 합니다.

    4. 휘발성 확장 문제(이해) )

    휘발성이 질서를 보장하지 않는다면 이중 확인 잠금을 작성하는 방식에 문제가 있습니까?

    새 개체에 대해서는 순서대로 3가지 명령으로 나뉩니다.

    (1) 개체의 메모리 공간 할당

    (2) 개체 인스턴스화

    (3) 변수에 할당

    정상 실행 순서는 (1) (2)(3)입니다. JVM은 (1)(3)(2)

    으로 순서를 최적화하고 재정렬할 수 있습니다.

    이 재정렬의 결과는 메모리 공간이 할당된 후 객체가 인스턴스화되기 전에 할당이 완료될 수 있습니다.
    이 잘못된 할당 후에는 instance==null이 설정되지 않으며 스레드는 완료되지 않은 인스턴스화 인스턴스를 보유하게 됩니다. . , 해당 속성과 메서드를 사용하면 오류가 발생합니다

    순서를 보장하기 위해 휘발성을 사용한 후:

    스레드가 (1)(2)(3)의 순서에 관계없이 새 객체를 생성하면 다음으로 얻은 인스턴스가 생성됩니다. 후속 스레드는 인스턴스화된
    CPU에는 휘발성 변수 작업을 기반으로 하는 CPU 수준 잠금 메커니즘이 있습니다((1)(2)(3)이 모두 실행되고 주 메모리에 다시 기록되도록 보장합니다. 그런 다음 다른 스레드가 변수에 대한 작업을 실행합니다.)

    위 내용은 Java 싱글톤 패턴의 스레드 안전 문제를 해결하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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