자바 언어 단일 모드 의 실현
첫 번 째, 기본 적 인 지연 생 성 방법
우 리 는 먼저 가장 간단 한 실현 방식 을 살 펴 보 자.
package com.example.hello;
public class Singleton {
private static Singleton instance;
private Singleton() { }
public static Singleton getInstance () {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void sayHelloToWorld () {
System.out.print("Hello, world");
}
}
이러한 실현 방식 에서 구조 함 수 는 private 로 밝 혀 졌 기 때문에 Singleton 류 의 대상 을 방문 하려 면 Singleton. getInstance () 를 통 해 만 이 루어 질 수 있 습 니 다. Singleton. getInstance () 를 통 해 대상 의 생 성 과정 을 제어 하면 Singleton 류 의 대상 은 한 번 만 만 만 들 수 있 습 니 다.정말 잘 이 루어 진 것 같 습 니 다.그런데 사실은?실제로 병발 환경 에서 이런 실현 방식 은 매우 취약 해 보인다.
이런 실현 방식 은 최종 조건 이 발생 할 것 이다.일반적으로 더 밑 에 있 는 관점 에서 볼 때 변 수 를 수정 하 는 과정 은 대체적으로 몇 가지 절차 로 구성 되 고 메모리 에서 변 수 를 읽 고 레지스터 까지 변 수 를 수정 한 다음 에 변 수 를 메모리 에 다시 쓴다 고 볼 수 있다.이 몇 단계 의 모든 두 단계 사이 에 실행 중인 스 레 드 는 시간 이 다 되 어 실행 을 종료 할 수 있 습 니 다.
이 케이스 의 경우 정적 은 인 스 턴 스 검사, 대상 생 성, 할당 과정 에서 발생 합 니 다.첫 번 째 스 레 드 ThreadA 가 Singleton. getInstance () 를 먼저 호출 한다 고 가정 하면 인 스 턴 스 가 null 인 것 을 발견 하고 대상 을 만 든 다음 에 인 스 턴 스 에 값 을 부여 합 니 다. 대상 을 만 들 거나 할당 이 완료 되 기 전 어느 순간 에 시간 영화 가 다 써 서 실행 을 종료 합 니 다.이때 다른 스 레 드 ThreadB 는 Singleton. getInstance () 를 호출 했 습 니 다. 인 스 턴 스 를 null 로 발견 하여 대상 이 VM 에서 유일 성 을 보장 할 수 없습니다.
두 번 째, 동기 화 지연 생 성 방법
package com.example.hello;
public class Singleton {
private static Singleton instance;
private Singleton() { }
public static synchronized Singleton getInstance () {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public synchronized void sayHelloToWorld () {
System.out.print("Hello, world");
}
}
이 방법 은 이전 방법 에 비해 기본적으로 각 방법 을 synchronized 로 만 설명 하 는 것 이다.그러나 이 작은 변경 은 스 레 드 안전성 을 잘 보장 할 수 있다.싱글 턴 getInstance () 는 대부분의 경우 잠 금 을 추가 할 필요 가 없 으 며, 직접 방법 을 synchronized 라 고 밝 히 면 잠 금 을 추가 하 는 비용 이 좀 든다 고 한다.그러나 자 물 쇠 를 추가 하 는 것 은 경쟁 에 자 물 쇠 를 추가 하 는 것 과 비 경쟁 에 자 물 쇠 를 추가 하 는 것 으로 나 눌 수 있다. 바로 어느 순간 에 여러 개의 스 레 드 가 동시에 자 물 쇠 를 빼 앗 는 것 이지 경쟁 에 자 물 쇠 를 추가 하 는 것 이 아니 라 어느 순간 에 하나의 스 레 드 만 그 자 물 쇠 를 빼 앗 는 것 이다.골동품 을 제외 하고 현대 의 JVM 에서 대부분 상황 에서 나타 날 비 경쟁 자 물 쇠 는 매우 빠 를 것 이다. 대략 몇 개 또는 10 여 개의 시계 주기 만 있 을 뿐 이 므 로 이곳 에서 의 이런 자 물 쇠 를 추가 하 는 비용 을 걱정 할 필요 가 거의 없다.
이와 함께 이런 방법 도 자바 와 함께 큰 소 가 추천 하 는 방법 이다.
세 번 째, 이중 검사 잠 금 방법
package com.example.hello;
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
public synchronized void sayHelloToWorld() {
System.out.print("Hello, world");
}
}
이런 방법 은 앞의 방법 에 비해 자 물 쇠 를 넣 는 비용 을 조금 낮 출 수 있다.그러나 인 스 턴 스 는 volatile 로 밝 혀 졌 음 을 주의해 야 한다.volatile 이 라 고 밝 히 지 않 으 면, 가시 적 인 문제 가 생 길 수 있다.JVM 이 제공 하 는 보증 은 그 코드 가 단일 작업 환경 에서 다 중 작업 환경 에서 실 행 됩 니 다. 최종 결 과 는 똑 같 습 니 다. JVM 이 무질서 한 실행 과 같은 최적화 조 치 를 취 할 지 여 부 를 상관 하지 않 습 니 다.따라서 할당 문 인 스 턴 스 = new Singleton () 은 좀 더 미시적 인 측면 에서 볼 때 대상 이 완전히 생 성 되 지 않 았 을 때 인 스 턴 스 가 대상 의 메모리 블록 을 가리 킬 수 있 습 니 다.따라서 다른 스 레 드 는 아직 완전히 만들어 지지 않 은 대상 을 볼 수 있 습 니 다.인 스 턴 스 를 volatile 로 성명 하면 이런 문 제 를 피 할 수 있다.
그러나 이런 모델 은 실현 되 기 시작 하면 좀 복잡 해 야 한다.
네 번 째, 지연 없 이 만 드 는 방법 (미리 초기 화)
package com.example.hello;
public class Singleton {
private static Singleton instance = new Singleton();;
private Singleton() { }
public static Singleton getInstance () {
return instance;
}
public synchronized void sayHelloToWorld () {
System.out.print("Hello, world");
}
}
다 중 스 레 드 문 제 를 피 할 수 있 는 또 다른 방법이러한 방법 은 classloader 의 메커니즘 을 빌려 정적 으로 만 드 는 방법 을 통 해 class 가 load 되 었 을 때 대상 을 만 들 고 뒤에서 Singleton. getInstance () 를 호출 할 때 잠 금 비용 이 필요 하지 않 습 니 다.그러나 이런 방법의 단점 도 분명 하 다.class 는 여러 가지 이유 로 load 될 수 있 지만 인 스 턴 스 는 Singleton. getInstance () 를 호출 한 후에 만 만 만 들 필요 가 있 습 니 다.그런 큰 싱글 톤 대상 에 대해 서 는 불필요 한 메모리, 프로세서 시간 등 자원 을 너무 많이 소모 할 수 있 습 니 다.
다섯 번 째, 지연 없 이 만 드 는 방법 2
package com.example.hello;
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public synchronized void sayHelloToWorld() {
System.out.print("Hello, world");
}
}
이런 방법 은 앞의 네 번 째 방법 과 똑같다 고 할 수 있다.
여섯 번 째, 정적 내부 클래스 방법
package com.example.hello;
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
public synchronized void sayHelloToWorld() {
System.out.print("Hello, world");
}
}
이 방법 은 앞의 초기 화 기술 과 JVM 의 지연 로드 체 제 를 결합 시 켜 흔히 볼 수 있 는 코드 경로 에 자 물 쇠 를 추가 하지 않 아 도 되 고 로드 를 지연 시 킬 수 있 는 기술 이다.그것 은 대상 을 초기 화 하기 위해 서 전문 적 인 Singleton Holder 를 사용 합 니 다.JVM 은 이러한 종류의 초기 화 작업 을 지연 시 키 고 이 종 류 를 사용 하기 시작 할 때 까지 초기 화 합 니 다. 또한 정적 초기 화 를 통 해 Singleton 을 초기 화 하기 때문에 추가 동기 화 를 필요 로 하지 않 습 니 다.모든 스 레 드 가 getInstance () 를 처음 호출 할 때 Singleton Holder 를 불 러 오고 초기 화 합 니 다. 이 때 정적 초기 화 기 는 Singleton 의 초기 화 를 실행 합 니 다.
Done。
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.