답변:
네, 필요합니다. 지연 초기화로 스레드 안전성을 달성하는 데 사용할 수있는 몇 가지 방법이 있습니다.
드라코 니안 동기화 :
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
이 솔루션을 사용하려면 실제로 처음 몇 개만 동기화 해야 할 때 모든 스레드를 동기화해야합니다.
동기화 재확인 :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
이 솔루션은 싱글 톤을 획득하려는 처음 몇 개의 스레드 만 잠금 획득 프로세스를 거치도록합니다.
요청시 초기화 :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
이 솔루션은 스레드 안전성을 보장하기 위해 클래스 초기화에 대한 Java 메모리 모델의 보장을 활용합니다. 각 클래스는 한 번만로드 할 수 있으며 필요할 때만로드됩니다. 즉, 처음 getInstance
호출되고 InstanceHolder
로드되고 instance
생성되며 ClassLoader
s에 의해 제어 되므로 추가 동기화가 필요하지 않습니다.
Draconian synchronization
및 Double check synchronization
getInstance () 메서드는 정적이어야합니다!
static
없지만 그들이 있다면 더 의미가있을 수 있습니다. 요청에 따라 수정되었습니다.
r
는 정확성을 위해 필요하지 않습니다. 지역 변수에 액세스하는 것보다 훨씬 비싸기 때문에 휘발성 필드에 액세스하는 것을 피하는 것은 최적화 일뿐입니다.
이 패턴은 명시 적 동기화 없이 인스턴스의 스레드로부터 안전한 지연 초기화를 수행합니다 !
public class MySingleton {
private static class Loader {
static final MySingleton INSTANCE = new MySingleton();
}
private MySingleton () {}
public static MySingleton getInstance() {
return Loader.INSTANCE;
}
}
클래스 로더를 사용하여 모든 동기화를 무료로 수행하기 때문에 작동합니다. 클래스 MySingleton.Loader
는 getInstance()
메서드 내에서 먼저 액세스 되므로 처음 호출 Loader
될 때 클래스가로드됩니다 getInstance()
. 또한 클래스 로더는 클래스에 액세스하기 전에 모든 정적 초기화가 완료되도록 보장합니다. 이것이 스레드 안전성을 제공하는 것입니다.
마법 같아요.
실제로 Jhurtado의 enum 패턴과 매우 유사하지만 enum 패턴이 enum 개념의 남용이라는 것을 알았습니다 (작동하지만)
final
. 끝난.
예, getInstance()
동기화 해야 합니다. 그렇지 않은 경우 클래스의 여러 인스턴스를 만들 수있는 상황이 발생할 수 있습니다.
getInstance()
동시에 호출하는 두 개의 스레드가있는 경우를 고려하십시오 . 이제 T1이 instance == null
검사를 통과 한 다음 T2가 실행된다고 상상해보십시오 . 이 시점에서 인스턴스가 생성되거나 설정되지 않았으므로 T2가 검사를 통과하고 인스턴스를 생성합니다. 이제 실행이 T1로 다시 전환된다고 상상해보십시오. 이제 싱글 톤이 생성되었지만 T1은 이미 확인을 완료했습니다! 다시 개체 만들기를 진행합니다! 제작 getInstance()
이 문제 동기화 방지합니다.
싱글 톤을 스레드로부터 안전하게 만드는 몇 가지 방법이 있지만 getInstance()
동기화하는 것이 아마도 가장 간단 할 것입니다.
싱글 톤 열거
스레드로부터 안전한 Singleton을 구현하는 가장 간단한 방법은 Enum을 사용하는 것입니다.
public enum SingletonEnum {
INSTANCE;
public void doSomething(){
System.out.println("This is a singleton");
}
}
이 코드는 Java 1.5에 Enum이 도입 된 이후로 작동합니다.
이중 확인 잠금
멀티 스레드 환경 (Java 1.5부터 시작)에서 작동하는 "클래식"싱글 톤을 코딩하려면이 싱글 톤을 사용해야합니다.
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null) {
instance = new Singleton();
}
}
}
return instance ;
}
}
volatile 키워드의 구현이 다르기 때문에 1.5 이전에는 스레드로부터 안전하지 않습니다.
싱글 톤 조기로드 (Java 1.5 이전에도 작동)
이 구현은 클래스가로드 될 때 싱글 톤을 인스턴스화하고 스레드 안전성을 제공합니다.
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public void doSomething(){
System.out.println("This is a singleton");
}
}
정적 코드 블록을 사용하여 클래스로드시 인스턴스를 인스턴스화하고 스레드 동기화 문제를 방지 할 수도 있습니다.
public class MySingleton {
private static final MySingleton instance;
static {
instance = new MySingleton();
}
private MySingleton() {
}
public static MySingleton getInstance() {
return instance;
}
}
instance
최종적으로 만들어야 getInstance()
합니다. 2. 당신은 정적으로 만들어야 합니다.
다중 스레드 환경에서 Java로 Singleton을 구현하는 가장 좋은 방법은 무엇입니까?
Singleton을 구현하는 가장 좋은 방법은이 게시물을 참조하십시오.
Java에서 싱글 톤 패턴을 구현하는 효율적인 방법은 무엇입니까?
여러 스레드가 동시에 getInstance () 메서드에 액세스하려고하면 어떻게됩니까?
메서드를 구현 한 방식에 따라 다르며, 휘발성 변수없이 이중 잠금을 사용하면 부분적으로 구성된 Singleton 객체를 얻을 수 있습니다.
자세한 내용은이 질문을 참조하십시오.
싱글 톤의 getInstance ()를 동기화 할 수 있습니까?
Singleton 클래스를 사용할 때 동기화가 정말로 필요합니까?
아래 방법으로 Singleton을 구현하는 경우 필요하지 않습니다.
자세한 내용은이 질문을 참조하십시오.