Java Concurrent Hashmap initTable () 왜 try / finally 블록입니까?

Aug 29 2020

나는 다음 코드를 보았습니다 ( 여기 에서 소스 ) '

/**
 * Initializes table, using the size recorded in sizeCtl.
 */
private final Node<K,V>[] initTable() {
    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
        if ((sc = sizeCtl) < 0)
            Thread.yield(); // lost initialization race; just spin
        else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
            try {
                if ((tab = table) == null || tab.length == 0) {
                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                    @SuppressWarnings("unchecked")
                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                    table = tab = nt;
                    sc = n - (n >>> 2);
                }
            } finally {
                sizeCtl = sc;
            }
            break;
        }
    }
    return tab;
}

누군가 try 블록이 필요한 이유를 설명 할 수 있습니까?

답변

3 rzwitserloot Aug 29 2020 at 20:31

확인되지 않은 예외 및 오류는 개념으로 존재합니다. .put()ConcurrentHashMap 을 호출 하고 메모리가 부족하면 해당 맵이 배열을 만들려고 할 수 있으며 해당 호출이 OutOfMemoryError로 실패 할 수 있습니다. 코드는 여전히 계속되고 (아마도 이것을 포착하는 catch 블록에서) 해당 맵에 대한 참조가 여전히 존재합니다. 그 후 sizeCtl에 깨진 값이 있기 때문에 맵이 충돌하고 완전히 무효화되면 약간의 문제가 될 수 있습니다.

요점은 sizeCtl값 을 복원하는 finally 블록 입니다. 이것은 액세스 권한을 얻는 스레드 관리를 포함하여 주목할만한 다양한 작업에 사용됩니다. 그렇지 않은 경우 다른 풋 콜은 영원히 회전합니다.

이것의 관련성 (예 : 여기에서 throwable이 발생하는 빈도와 'try'및 'finally'를 제거하고 sizeCtl = sc;try / finally의 추가 오버 헤드없이 끝나는 경우)는 낮지 만 관련성이있는 경우 상당히 관련이 있습니다.

Den-Jason Aug 29 2020 at 20:32

이것은 일종의 뮤텍스이며 이중 확인 잠금입니다.

첫째로

if ((sc = sizeCtl) < 0)
    Thread.yield(); // lost initialization race; just spin

sizeCtl뮤텍스를 확인합니다 . 0보다 작 으면 다른 사람이 잡은 것이므로 잠시 기다립니다.

0 (또는 그 이상)이면 잠금을 얻을 가능성이 있습니다. 따라서 Compare-And-Swap이 수행됩니다.

if (U.compareAndSetInt(this, SIZECTL, sc, -1)

이것은 원자 적 작업입니다. 다른 스레드가 첫 번째 검사와 두 번째 검사 사이에 그것을 잡았다면은 if취해지지 않을 것입니다.

CAS가 성공하면 메서드가 뮤텍스를 해제 할 책임이 있습니다. 따라서 a try-finallysizeCtl예외가 발생하는지 (예 : 새 노드를 할당하는 메모리 부족-또는 맵에 적용 할 수있는 고유 한 제한이있는 경우) 여부에 관계없이 뮤텍스가 해제 ( 원래 값으로 재설정) 되도록하는 데 사용됩니다 .