자바 단일 모드 의 8 가지 쓰기(추천)
굶 주 린 한 사례 디자인 모델
1.굶 주 린 남자 디자인 모델
public class SingletonHungry {
private final static SingletonHungry INSTANCE = new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return INSTANCE;
}
}
단일 대상 이 처음부터 초기 화 되 었 기 때문에 스 레 드 안전 에 문제 가 생기 지 않 습 니 다.PS:우 리 는 1 회 만 초기 화 할 수 있 기 때문에 INSTANCE 에
final
키 워드 를 추가 하여 1 회 초기 화 후 초기 화 를 허용 하지 않 음 을 표시 합 니 다.게으름뱅이 단일 디자인 모델
2.단순 게으름뱅이 디자인 모델
굶 주 린 사람 모드 는 처음부터 초기 화 되 었 지만 계속 사용 되 지 않 으 면 소중 한 메모리 자원 을 낭비 할 수 있 기 때문에 게 으 른 사람 모드 를 이 끌 어 냈 다.
게으름뱅이:처음 사용 할 때 만 대상 을 예화 합 니 다.
public class SingletonLazy1 {
private static SingletonLazy1 instance;
private SingletonLazy1() {
}
public static SingletonLazy1 getInstance() {
if (instance == null) {
instance = new SingletonLazy1();
}
return instance;
}
}
테스트:
public class Main {
public static void main(String[] args) {
SingletonLazy1 instance1 = SingletonLazy1.getInstance();
SingletonLazy1 instance2 = SingletonLazy1.getInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
테스트 결과:결과 에서 알 수 있 듯 이 인쇄 된 두 개의 인 스 턴 스 대상 주 소 는 같 기 때문에 하나의 대상 만 만 만 들 었 다 고 생각 합 니 다.3.진급
1:다 중 스 레 드 병행 문제 해결
상기 코드 에 존재 하 는 문제점:다 중 스 레 드 환경 에서 하나의 인 스 턴 스 만 만 들 수 없습니다.우 리 는 문제 의 재현 을 진행 합 니 다.
public class Main {
public static void main(String[] args) {
new Thread(()-> System.out.println(SingletonLazy1.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy1.getInstance())).start();
}
}
결과:얻 은 대상 이 다 릅 니 다.이것 은 우리 가 예상 한 결과 가 아 닙 니 다.해결 방안:
public class SingletonLazy2 {
private static SingletonLazy2 instance;
private SingletonLazy2() {
}
// synchronized
public static synchronized SingletonLazy2 getInstance() {
if (instance == null) {
instance = new SingletonLazy2();
}
return instance;
}
}
테스트:
public class Main2 {
public static void main(String[] args) {
new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
}
}
결과:다 중 스 레 드 환경 에서 같은 대상 을 얻 었 습 니 다.
4.진급 2:축소 방법 잠 금 입도
이전 방안 은 다 중 스 레 드 문 제 를 해결 하 였 으 나 synchronized 키 워드 는 방법 에 추 가 된 것 이기 때문에 잠 금 입도 가 매우 크 고 수만,심지어 더 많은 스 레 드 가 동시에 방문 할 때 방법 밖 에 막 혀 프로그램의 성능 을 크게 떨 어 뜨 렸 기 때문에 우 리 는 잠 금 입 도 를 적당 하 게 줄 이 고 잠 금 의 범 위 를 코드 블록 에 제어 해 야 한다.
public class SingletonLazy3 {
private static SingletonLazy3 instance;
private SingletonLazy3() {
}
public static SingletonLazy3 getInstance() {
// 1: if ,
if (instance == null) {
// 2: ,
synchronized (SingletonLazy3.class) {
// 3
instance = new SingletonLazy3();
}
}
return instance;
}
}
테스트:
public class Main3 {
public static void main(String[] args) {
new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
}
}
실행 결 과 를 살 펴 보 겠 습 니 다.아니면 스 레 드 안전 에 문제 가 생 겼 습 니까?원인 분석:스 레 드 A 가 자 물 쇠 를 가 져 와
3
에 들 어가 고 인 스 턴 스 를 만 들 지 않 았 을 때 스 레 드 B 는 도착 할 기회 가 있 습 니 다 2
.이때 스 레 드 C 와 D 는 1
에 있 을 수 있 습 니 다.스 레 드 A 가 실 행 된 후에 자 물 쇠 를 풀 고 대상 1 로 돌아 갑 니 다.스 레 드 B 가 들 어가 3
새로운 대상 2 커버 대상 1 을 만 들 고 돌아 갑 니 다.마지막 으로 스 레 드 C 와 D 가 null 을 판단 할 때 인 스 턴 스 가 비어 있 지 않 은 것 을 발견 하고 마지막 으로 만 든 대상 2 를 되 돌려 줍 니 다.5.진급 3:잠 금 DCL 이중 검사(Double-Checked-Locking)
이중 검사 자물쇠 란 스 레 드 에서 자 물 쇠 를 가 져 온 후에 인 스 턴 스 를 두 번 째 로 빈 칸 으로 검사 하 는 것 입 니 다.이전 스 레 드 가 이미 예화 되 었 는 지 판단 하고 있 으 면 바로 돌아 가면 됩 니 다.그렇지 않 으 면 인 스 턴 스 를 초기 화 합 니 다.
public class SingletonLazy4DCL {
private static SingletonLazy4DCL instance;
private SingletonLazy4DCL() {
}
public static SingletonLazy4DCL getInstance() {
// 1:
if (instance == null) {
// 2: ,
synchronized (SingletonLazy3.class) {
// 3: ( )
if (instance == null) {
instance = new SingletonLazy4DCL();
}
}
}
return instance;
}
}
테스트:
public class Main4DCL {
public static void main(String[] args) {
new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
}
}
6,진급 4:명령 정렬 금지
대상 의 인 스 턴 스 과정 에서 다음 과 같은 세 단계 로 나 눌 수 있 습 니 다.
해결:instance 에
volatile
키 워드 를 추가 하면 명령 을 다시 배열 하 는 것 을 금지 하고 나타 날 확률 이 크 지 않 지만 이것 은 더욱 안전 한 방법 입 니 다.
public class SingletonLazy5Volatile {
// volatile
private volatile static SingletonLazy5Volatile instance;
private SingletonLazy5Volatile() {
}
public static SingletonLazy5Volatile getInstance() {
// 1
if (instance == null) {
// 2: ,
synchronized (SingletonLazy3.class) {
// 3
if (instance == null) {
instance = new SingletonLazy5Volatile();
}
}
}
return instance;
}
}
7.진급 5:정적 내부 클래스정적 클래스 의 정적 변 수 를 사용 하여 첫 번 째 방문 시 초기 화 할 수 있 습 니 다.외부 클래스 의 단일 대상 을 정적 내부 클래스 의 정적 구성원 변수 에 넣 어 초기 화 합 니 다.
public class SingletonLazy6InnerStaticClass {
private SingletonLazy6InnerStaticClass() {
}
public static SingletonLazy6InnerStaticClass getInstance() {
return SingletonLazy6InnerStaticClass.InnerStaticClass.instance;
// return InnerStaticClass.instance;
}
private static class InnerStaticClass {
private static final SingletonLazy6InnerStaticClass instance = new SingletonLazy6InnerStaticClass();
}
}
정적 내부 클래스 의 쓰기 방식 은 굶 주 린 사람 모드 와 비슷 하지만 외부 클래스 가 불 러 올 때 초기 화 되 는 것 이 아니 라 처음 방문 할 때 초기 화 되 는 작업(즉 getInstance 방법 이 호출 될 때)도 게 으 른 로 딩 효 과 를 내 고 스 레 드 안전 을 확보 할 수 있 습 니 다.테스트:
public class Main6InnerStatic {
public static void main(String[] args) {
new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
}
}
반사 공격
비록 우 리 는 처음에 구조 기 를 사유 화 처 리 했 지만 자바 자체 의 반사 체 제 는 private 방문 권한 을 방문 가능 으로 바 꿀 수 있 고 새로운 인 스 턴 스 대상 을 만 들 수 있 습 니 다.여 기 는 굶 주 린 사람 모델 로 예 를 들 어 설명 합 니 다.
public class MainReflectAttack {
public static void main(String[] args) {
try {
SingletonHungry normal1 = SingletonHungry.getInstance();
SingletonHungry normal2 = SingletonHungry.getInstance();
//
Constructor<SingletonHungry> reflect = SingletonHungry.class.getDeclaredConstructor(null);
reflect.setAccessible(true);
SingletonHungry attack = reflect.newInstance();
System.out.println(" :");
System.out.println(normal1);
System.out.println(normal2);
System.out.println(" :");
System.out.println(attack);
} catch (Exception e) {
e.printStackTrace();
}
}
}
8.매 거 사례(추천 사용)
public enum SingletonEnum {
INSTANCE;
}
매 거 진 것 은 가장 간결 하고 스 레 드 가 안전 하 며 반사 되 지 않 고 인 스 턴 스 를 만 드 는 단일 사례 로 이 루어 집 니 다.에서 도 이러한 기법 이 가장 좋 은 단일 사례 실현 모델 임 을 나 타 냈 습 니 다.단일 요소 의 매 거 유형 은 항상 싱글 턴 을 실현 하 는 가장 좋 은 방법 이 된다.-'Effective Java》
왜 반사 되 지 않 고 대상 을 만든다 고 하 죠?구조 기 반사 실례 화 대상 방법
newInstance
의 원본 코드 를 보면 알 수 있 듯 이 반사 가 매 거 진 대상 의 실례 화 를 금지 하고 반사 공격 을 방지 하 며 스스로 구조 기 에서 복잡 한 중복 실례 화 논 리 를 실현 하지 않 아 도 된다.테스트:
public class MainEnum {
public static void main(String[] args) {
SingletonEnum instance1 = SingletonEnum.INSTANCE;
SingletonEnum instance2 = SingletonEnum.INSTANCE;
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
결론:몇 가지 실현 방식 의 장단 점 게으름뱅이 모델
장점:메모리 절약.
단점:스 레 드 안전 문제 가 존재 합 니 다.스 레 드 안전 을 확보 하려 면 쓰기 가 복잡 합 니 다.
굶 주 린 남자 모델
장점:스 레 드 안전.
단점:단일 대상 이 계속 사용 되 지 않 으 면 메모리 공간 이 낭비 된다.
정적 내부 클래스
장점:게 으 름 을 피 우 고 다 중 스 레 드 문 제 를 피 할 수 있 습 니 다.게 으 른 사람 보다 쓰기 가 더 간단 합 니 다.
단점:내부 클래스 를 하나 더 만들어 야 합 니 다.
매 거
장점:간결 하고 타고 난 스 레 드 가 안전 하 며 반사 적 으로 인 스 턴 스 를 만 들 수 없습니다.
단점:없 음
자바 단일 모드 에 관 한 8 가지 문법 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 단일 모드 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.