싱글톤 패턴은 23가지 디자인 패턴 중 하나로, 생성자를 사유화하여 몇 번이나 호출해도 동일한 객체를 반환하는 것이 목적이다.
두 가지 구조로 나뉘는데, 하나는 게으른 남자 스타일이고 다른 하나는 배고픈 남자 스타일입니다. 각각의 장점과 단점이 있습니다. 코드는 다음과 같습니다.
공용 클래스 단일 { 개인 정적 단일 단일 = 새 단일(); 개인 단일() { } 공공 단일 getInstance() { 반환 단일;
위의 프로그램에서 볼 수 있듯이 동일한 개체를 로드하려는 목적은 실제로 달성되었지만 프로그램이 로드될 때 단일 개체가 생성됩니다. 이 클래스에 이러한 메서드가 여러 개 있으면 대부분의 싱글톤을 사용하지 않을 수 있습니다. 이 개체에서는 메모리 낭비가 발생합니다. 그래서 게으른 싱글톤 패턴이 등장했습니다. 코드는 다음과 같습니다.
공용 클래스 단일 { 개인 정적 단일 단일 = null; 개인 단일() { } 공공 단일 getInstance() { if(single==null){ 단일 = 새로운 단일() } 반환 단일;
이렇게 하면 실제로 호출할 때만 객체가 새로워지는데 여기에는 문제가 있습니다.
위의 두 번째 코드가 처음 로드될 때 두 개의 스레드에 의해 호출되면 서로 다른 두 개의 개체가 생성되므로 스레드 안전하지 않습니다. 이때 잠금 후 코드인 Lock을 추가하는 것을 생각하게 됩니다. 다음과 같습니다:
공용 클래스 단일 { 개인 정적 단일 단일 = null; 개인 단일() { } 공용 동기화 단일 getInstance() { if (단일 == null) { 단일 = 새로운 단일() } 반환 단일;
이는 스레드 안전성을 달성하지만 잠금 메서드가 많은 작업을 수행해야 하는 경우 이 메서드를 호출하는 데 시간이 오래 걸리고 이는 서버에 치명적입니다. 스레드가 이 메서드를 계속 호출하면 조정할 방법이 없기 때문입니다. 다른 스레드와 서버가 차단됩니다. 그러면 업그레이드된 코드는 다음과 같습니다.
공용 클래스 Single { priate static Single Single = null; private Single() { } public Single getInstance() { if (single == null) { synced (Single.class) { Single = new Single() } return Single; } }
주의깊게 관찰한 결과 이런 식으로는 잠금이 없다는 것을 알았습니다. 처음으로 판단하면 두 스레드가 getInstance() 메서드에 도착하면 다른 스레드가 실행을 완료한 후 차단되어야 합니다. 더 이상 비어 있는지 확인하기 위해 객체가 생성됩니다. 이러한 방식으로 여러 객체가 생성된 후 결과 코드는 다음과 같습니다.
공용 클래스 단일 { 개인 정적 단일 단일 = null; 개인 단일() { } 공공 단일 getInstance() { if (단일 == null) { 동기화됨 (Single.class) { if (단일 == null) { 단일 = 새 단일 (); } } } 싱글 반환 } }
이렇게 하면 위의 문제가 발생하지 않고 한 번만 잠기게 되는데, 두 번째로 메소드가 실행될 때 if 판단을 건너뛰고 싱글이 직접 반환되지 않기 때문입니다. , 실행 효율성이 매우 높을 것입니다.
그러나 그럼에도 불구하고 객체에 메모리에 값이 먼저 할당되는지 아니면 객체가 먼저 생성되는지 확신할 수 없으므로 두 번째 프로그램이 jdk1에서 절반 초기화된 객체를 얻을 수 있기 때문에 여전히 문제가 있습니다. , 이 상황을 피하기 위해 휘발성 키워드를 사용할 수 있습니다. 코드는 다음과 같습니다.
공용 클래스 단일 { 개인 정적 휘발성 단일 단일 = null 개인 Single() { } 공용 단일 getInstance() { if (단일 == null) { 동기화됨 (Single.class) { if (단일 == null) { 단일 = 신규 싱글() } } } 싱글 반환 } }
하지만 이런 상황은 거의 사용되지 않습니다. 저는 단지 배우기 위해 여기에 왔습니다.