code

싱글 톤의 이중 체크 잠금

codestyles 2020. 12. 1. 08:03
반응형

싱글 톤의 이중 체크 잠금


여기 싱글 톤 패턴에 대한 커스텀 클래스가 있습니다. 이 코드에서는 아래와 같이 이중 확인 잠금을 사용합니다. 일부 소스에서 많은 게시물을 읽었을 때 두 개의 동시 스레드가 동시에 실행되는 것을 방지하여 두 개의 다른 개체를 만드는 것을 방지하기 때문에 이중 검사가 유용하다고 말합니다.

public class DoubleCheckLocking {

    public static class SearchBox {
        private static volatile SearchBox searchBox;

        // private constructor
        private SearchBox() {}

        // static method to get instance
        public static SearchBox getInstance() {
            if (searchBox == null) { // first time lock
                synchronized (SearchBox.class) {
                    if (searchBox == null) {  // second time lock
                        searchBox = new SearchBox();
                    }
                }
            }
            return searchBox;
        }
}

나는 여전히 위의 코드를 너무 많이 이해하지 못합니다. 인스턴스가 null 일 때 두 스레드가 함께 동일한 코드 줄을 실행하면 문제는 무엇입니까?

if (searchBox == null) {
                synchronized (SearchBox.class) {
                    if (searchBox == null) {
                        searchBox = new SearchBox();
                    }
                }
            }

그것이 나타날 때. 두 스레드 모두 object is null을 보게됩니다. 그런 다음 둘 다 동기화합니다. 그런 다음 다시 확인하고 여전히 null을 봅니다. 두 개의 다른 개체를 만듭니다. OOOPS.

설명해주세요. 내가 무엇을 잘못 이해 했습니까?

감사 :)


아니요,에서 잠금을 얻고 있으므로 SearchBox.class한 번에 하나의 스레드 만 동기화 된 블록에 들어갑니다. 따라서 첫 번째 스레드가 입력하면 searchBoxnull이 발견 되고 생성 된 다음 동기화 된 블록을 떠난 다음 두 번째 스레드가 블록에 들어간 다음 searchBox첫 번째 스레드가 이미 생성했기 때문에이 (가) null이 아님을 발견 하므로 새 인스턴스를 생성하지 않습니다. searchBox.

이중 체크 패턴은 코드가 실행될 때마다 잠금을 얻지 않도록하기 위해 사용됩니다. 호출이 함께 발생하지 않으면 첫 번째 조건이 실패하고 코드 실행이 잠금을 실행하지 않으므로 리소스가 절약됩니다.


이 코드를 살펴 보겠습니다.

1 if (searchBox == null) {
2     synchronized (SearchBox.class) {
3     if (searchBox == null) {
4         searchBox = new SearchBox();
5     }
6 }

이것에 대해 추론 해 봅시다. 두 개의 스레드가 A있고 B그 중 적어도 하나가 라인 3에 도달하고 관찰되는 스레드 searchBox == nulltrue. 블록 으로 인해 두 개의 스레드 가 동시에 라인 3에있을 수 없습니다synchronized . 이것이 이중 확인 잠금이 작동하는 이유를 이해 하는 열쇠 입니다. 따라서 먼저 A또는 먼저 B통과 한 경우 여야합니다 synchronized. 일반성을 잃지 않고 해당 스레드가 A. 그런 다음 searchBox == nulltrue를 확인하면 문의 본문에 입력하고 searchBox의 새 인스턴스로 설정 합니다 SearchBox. 그런 다음 결국 synchronized블록을 종료합니다 . 이제 B들어갈 차례입니다. 기억하세요.BA종료를 기다리는 동안 차단되었습니다 . 이제 블록에 들어가면 searchBox. 그러나 이 아닌 값으로 A설정 searchBox하면 남을 것 null입니다. 끝난.

그런데 Java에서 싱글 톤을 구현하는 가장 좋은 방법은 단일 요소 enum유형 을 사용하는 것 입니다. 에서 효과적인 자바 :

이 접근 방식은 아직 널리 채택되지 않았지만 단일 요소 열거 형은 단일 항목을 구현하는 가장 좋은 방법입니다.


이 이중 검사 잠금은 싱글 톤을 동시에 호출하는 스레드가 많거나 일반적으로 잠금을 얻는 비용이 걱정되는 경우에만 필요합니다.

그 목적은 불필요한 동기화를 방지하여 다중 스레드 환경에서 코드를 빠르게 유지하는 것입니다.

자세한 내용은이 링크를 확인하십시오.

If you are running in Java 1.5 or greater, and you use the volatile keyword in your double-check locked mechanism, it will work fine. As you are using the volatile keyword, your example is not broken according to the same link above.


if (searchBox == null) { //1
    synchronized (SearchBox.class) {
        if (searchBox == null) {  //2
            searchBox = new SearchBox();
            }
        }
    }
}
  1. If an instance was already created, don't do anything - avoid locking threads
  2. The first thread that has acquired the lock checks and sees that there is no such object and creates it. It releases the lock and the second one can do the same - it has to check if the object exists because the first one may have created it.

So basically the outer if is used to prevent redundant locks - it lets all thread know that there is already an object and they don't need to lock/do anything. And the inner if is used to let a concurrent thread know whether another has already created the object or not.

참고URL : https://stackoverflow.com/questions/18093735/double-checked-locking-in-singleton

반응형