잘못된 지연 초기화
Findbug는 잘못된 지연 초기화를 사용한다고 말했습니다.
public static Object getInstance() {
if (instance != null) {
return instance;
}
instance = new Object();
return instance;
}
나는 여기서 잘못된 것을 보지 않는다. findbug의 잘못된 동작입니까, 아니면 뭔가 놓쳤습니까?
Findbug는 잠재적 인 스레딩 문제를 참조하고 있습니다. 다중 스레드 환경에서는 현재 코드로 싱글 톤이 두 번 이상 생성 될 가능성이 있습니다.
이 독서의 많은입니다 여기가 있지만, 설명하는 데 도움이됩니다.
여기서 경쟁 조건은에 있습니다 if check
. 첫 번째 호출에서 스레드는에 들어가 if check
인스턴스를 만들고 '인스턴스'에 할당합니다. 그러나 if check
인스턴스 생성 / 할당과 사이에 다른 스레드가 활성화 될 가능성이 있습니다. 이 스레드 if check
는 할당이 아직 발생하지 않았기 때문에를 전달할 수도 있습니다 . 따라서 두 개 (또는 더 많은 스레드가 들어온 경우 그 이상) 인스턴스가 생성되고 스레드는 다른 개체에 대한 참조를 갖게됩니다.
코드가 필요한 것보다 약간 복잡하기 때문에 혼란 스러울 수 있습니다.
편집 : 다른 사람들이 게시 한 것처럼 확실히 스레딩 문제이지만 아래에 참조를 위해 이중 잠금 확인 구현을 게시 할 것이라고 생각했습니다.
private static final Object lock = new Object();
private static volatile Object instance; // must be declared volatile
public static Object getInstance() {
if (instance == null) { // avoid sync penalty if we can
synchronized (lock) { // declare a private static Object to use for mutex
if (instance == null) { // have to do this inside the sync
instance = new Object();
}
}
}
return instance;
}
참고 : JohnKlehm의 이중 잠금 검사 솔루션이 더 좋습니다. 이 답변은 역사적인 이유로 여기에 남겨 둡니다.
실제로는
public synchronized static Object getInstance() {
if (instance == null) {
instance = new Object();
}
return instance;
}
이를 수정하려면 인스턴스화 주위에 잠금을 설정해야합니다.
LI : 정적 필드의 잘못된 지연 초기화 (LI_LAZY_INIT_STATIC)
이 메서드에는 비 휘발성 정적 필드의 동기화되지 않은 지연 초기화가 포함되어 있습니다. 컴파일러 또는 프로세서가 명령어를 재정렬 할 수 있기 때문에 여러 스레드에서 메서드를 호출 할 수있는 경우 스레드가 완전히 초기화 된 개체를 볼 수 있다고 보장 할 수 없습니다. 문제를 해결하기 위해 필드를 휘발성으로 만들 수 있습니다. 자세한 내용은 Java Memory Model 웹 사이트를 참조하십시오.
게시 된 샘플에 대해 John Klehm에게 감사드립니다.
또한 동기화 된 블록의 개체 인스턴스를 직접 할당하려고 시도 할 수 있습니다.
synchronized (MyCurrentClass.myLock=new Object())
즉
private static volatile Object myLock = new Object();
public static Object getInstance() {
if (instance == null) { // avoid sync penalty if we can
synchronized (MyCurrentClass.myLock**=new Object()**) { // declare a private static Object to use for mutex
if (instance == null) { // have to do this inside the sync
instance = new Object();
}
}
}
return instance;
}
다중 스레딩 문제를 놓쳤습니다.
private static Object instance;
public static synchronized Object getInstance() {
return (instance != null ? instance : (instance = new Object()));
}
정적 개체가 동기화되지 않았습니다. 또한 귀하의 방법은 지연 초기화가 아닙니다. 일반적으로 당신이하는 일은 당신이 객체의지도를 유지하고, 당신은 요구에 따라 원하는 것을 초기화하는 것입니다. 따라서 필요할 때 호출 (호출)하는 것보다 처음에 모두 초기화하지 않습니다.
1.5 이후 : 인스턴스는 휘발성이어야하며 생성 된 인스턴스를 사용하지 않도록 tmp 변수를 통합해야하지만 초기화가 아직 완료되지 않았습니다.
private static volatile Object myLock = new Object();
private static volatile Object instance;
public static Object getInstance() {
if (instance == null) {
Object tmpObj;
synchronized (myLock) {
tmpObj = instance;
if (tmpObj == null) {
tmpObj = new Object();
}
}
instance = tmpObj;
}
return instance;
}
참조 URL : https://stackoverflow.com/questions/6782660/incorrect-lazy-initialization
'IT이야기' 카테고리의 다른 글
동일한 신호에 대한 여러 bash 트랩 (0) | 2021.04.10 |
---|---|
matcher의 그룹 방법을 사용할 때 "일치하지 않음" (0) | 2021.04.10 |
Xcode가 내 앱을 컴파일하지만 시뮬레이터에서 실행할 수 없습니다. (0) | 2021.04.09 |
JavaDoc에서 재정의 된 메서드 (0) | 2021.04.09 |
명령 줄을 통해 Git 커밋 메시지에 아포스트로피 (작은 따옴표) 사용 (0) | 2021.04.09 |