>  기사  >  Java  >  Java에서 이중 확인 잠금 문제를 해결하는 방법

Java에서 이중 확인 잠금 문제를 해결하는 방법

PHPz
PHPz앞으로
2023-04-18 11:31:041608검색

이중 검사 잠금의 기원

먼저 스레드로부터 안전하지 않은 초기화 싱글턴 모드를 살펴보겠습니다

	public class UnsafeLazyInitialization {
		private static UnsafeLazyInitialization instance;

		public static UnsafeLazyInitialization getInstance(){
			if(instance == null){                           //1:  线程A执行
				instance = new UnsafeLazyInitialization();  //2: 线程B执行
			}
			return instance;
		}
	}

UnsafeLazyInitialization 클래스에서 스레드 A가 코드 1을 실행하면 스레드 B가 코드 2를 실행한다고 가정합니다. 시간 스레드 A는 인스턴스 참조 개체가 아직 초기화되지 않았음을 확인할 수 있습니다.

UnsafeLazyInitialization 클래스의 경우 getInstance() 메서드를 동기화하여 스레드로부터 안전한 지연 초기화를 달성할 수 있습니다. 샘플 코드는 다음과 같습니다.

	public static synchronized  UnsafeLazyInitialization getInstance(){
			if(instance == null){                           //1:  线程A执行
				instance = new UnsafeLazyInitialization();  //2: 线程B执行
			}
			return instance;
		}
	}

위 코드는 getInstance() 메서드를 동기화하므로 이로 인해 동기화 프로그램이 발생할 수 있습니다. 오버헤드가 증가합니다. getInstance()를 여러 스레드에서 자주 호출하면 프로그램 실행 성능이 저하되고, 반대로 여러 스레드에서 호출되지 않으면 getInstance() 메서드의 초기화 방식이 지연되어 성능에 영향을 미치게 됩니다.

JVM 1.6 이전에는 동기화가 무거운 잠금이므로 성능을 많이 소모하므로 사람들은 성능 향상을 위해 이중 확인 잠금(Dobule-check Locking) 솔루션을 생각했습니다. 샘플 코드는 다음과 같습니다.

	public class DoubleCheckedLocking {                                 //1、
		private static Instance instance;                               //2、
		public static Instance getInstance(){                          //3、
			if(instance == null){                                      //4、第一次检查
				synchronized (DoubleCheckedLocking.class){              //5、枷锁
					if(instance == null){                                //6、第二次检查
						instance = new Instance();                       //7、问题的根源在这里
					}                                                    //8、
				}
			}
			return instance;
		}
	}

위 코드에 표시된 것처럼 4단계의 첫 번째 검사가 null이 아닌 경우 다음 잠금 작업을 수행할 필요가 없으므로 동기화된 잠금으로 인해 발생하는 성능 문제가 크게 줄어듭니다. 위의 코드에는 문제가 없는 것 같습니다. 1. 여러 스레드 보기가 새 개체를 생성할 때 동기화 키워드를 사용하면 단 하나의 스레드만 개체를 ​​성공적으로 생성하도록 할 수 있습니다.

2. 인스턴스 객체가 생성되었다면 getInstatnce() 메소드를 통해 직접 객체 인스턴스를 얻어옵니다.

위의 이중 확인 잠금 문제

위 코드는 완벽해 보이지만 4단계가 실행되면 즉시 실행됩니다! =null, 인스턴스의 참조 개체가 아직 초기화되지 않았을 수 있습니다.

문제의 근원

위의 7단계 코드를 실행하면, object = new Instance();가 생성되는데, 이 객체 생성 단계는 다음과 같이 세 단계로 나눌 수 있습니다.

위의 코드 2와 3의 세 줄은 순서가 바뀔 수 있습니다. (JTI 컴파일러에서는 실제로 순서가 바뀌는 일이 발생합니다.) 2단계와 3단계를 순서대로 바꾼 후의 실행 순서

	memory = allocate()  //1.分配内存空间memory
	ctorInstance(memory) //2, 初始化对象在内存 分配内存空间memory上初始化 Singleton 对象
	instance = memory //3、设置 instance 指向刚分配的内存地址memory
멀티 스레드 실행 순서를 살펴보겠습니다.

Java에서 이중 확인 잠금 문제를 해결하는 방법

Java에서 이중 확인 잠금 문제를 해결하는 방법

Instance = new Instance() 위 코드의 라인 7에서 스레드 A가 명령어 재정렬(2,3)을 발생하면 다른 스레드 B는 인스턴스가 라인 4에서 비어 있지 않다고 판단할 수 있습니다. 암호. 다음으로 스레드 B는 인스턴스의 참조 개체에 액세스하지만 인스턴스 개체는 A에 의해 초기화되지 않았을 수 있습니다. 이때 스레드 B가 초기화되지 않은 개체에 접근하여 널 포인터 오류가 발생할 수 있습니다.

문제 해결

1. 2와 3의 명령 재배열은 허용되지 않습니다. 2. 2와 3의 재정렬을 허용하지만 다른 스레드가 재정렬을 볼 수 없도록 허용

휘발성 기반 솔루션

위 코드를 기반으로 그림과 같이 인스턴스 선언에 휘발성 키워드만 추가하면 됩니다. 아래

	memory = allocate()  //1.分配内存空间memory
	instance = memory //3、设置 instance 指向刚分配的内存地址memory
									// 注意此时instance对象还没有被初始化,但是instance的引用已经不是null了。
	ctorInstance(memory) //2, 初始化对象在内存 分配内存空间memory上初始化 Singleton 对象

위 내용은 Java에서 이중 확인 잠금 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제