잠금 성능 향상에 도움이 되는 몇 가지 제안
잠금 유지 시간 줄이기
필요한 경우에만 동기화하여 잠금 유지 시간을 크게 줄이고 잠금 충돌 가능성 및 동시성 향상
For 예를 들어, 동기화 동기화 잠금을 사용하고, 개체가 변수 상태를 공유해야 할 때 추가해 보세요. 전체 메서드 앞에 맹목적으로 동기화를 추가하는 대신 이 메서드를 호출하는 개체를 직접 잠그면 잠금 경쟁 가능성이 높아집니다.
효율성을 높이기 위해 ReadWriteLock 읽기-쓰기 분리를 사용하는 것에 대해 이야기했는데,
이는 잠금 분리 전략으로 더욱 확장됩니다.
배타적 잠금 분리 기술에 대한 일반적인 참조 장면은 LinkedBlockingQueue 작업입니다. 이전에 말했듯이 연결 목록을 기반으로 구현된 무제한 작업 대기열입니다. take() 메서드와 put() 메서드는 각각 대기열의 프런트 엔드와 테일 엔드에서 작동하며 상호 보완적인 효과를 갖습니다. JDK에서는 구현 시 이 두 작업에 대해 두 개의 잠금이 제공됩니다.
예를 들어 put() 작업의 다중 스레드 실행에는 putLock에 대한 경쟁이 가장 많이 필요하고 take 작업은 리소스 잠금에 대해 경쟁합니다. 잠금에 대한 일회성 요청에 통합될 수 있으므로 애플리케이션 및 릴리스 작업 소비가 줄어듭니다.
/** Lock held by take, poll, etc */ private final ReentrantLock takeLock = new ReentrantLock(); /** Wait queue for waiting takes */ private final Condition notEmpty = takeLock.newCondition(); /** Lock held by put, offer, etc */ private final ReentrantLock putLock = new ReentrantLock(); /** Wait queue for waiting puts */ private final Condition notFull = putLock.newCondition();
for(int i=0;i<n;i++){ synchronized(lock){} }
에 최적화되어 있습니다.
이 기술의 일반적인 응용 시나리오는 HashMap과 비교할 때 스레드로부터 안전하고 HashTable과 비교할 때입니다. 효율적인 동시성
Segment 클래스는 ReentrantLock 클래스
에서 상속되므로 잠금을 획득할 때 잠금을 직접 사용하지 않습니다. 왜냐하면 이 메서드는 잠금 획득에 실패할 경우 중단되기 때문입니다. 실제로는문제: 교차 세그먼트 작업이 필요한 경우, 즉 시스템이 전역 잠금을 획득해야 하는 경우 모든 세그먼트의 잠금을 성공적으로 획득해야만 각 세그먼트의 잠금 상태를 확인해야 합니다. 글로벌 정보를 얻을 수 있습니다. 예를 들어 ConcurrentHashMap의 size() 메소드에는 모든 하위 세그먼트의 잠금이 필요합니다
CAS넣기 작업의 경우 키에 해당하는 배열 요소가 null이면 다음으로 설정됩니다. CAS 연산을 통해 현재 값. Key에 해당하는 배열 요소(즉, 연결 리스트의 헤드 또는 트리의 루트 요소)가 null이 아닌 경우에는 동기화 키워드를 사용하여 해당 요소에 잠금을 적용한 후 작업을 수행합니다. Put 작업으로 인해 현재 연결된 목록의 길이가 특정 임계값을 초과하는 경우 연결된 목록을 트리로 변환하여 주소 지정 효율성을 향상시킵니다.
읽기 작업의 경우 휘발성 키워드로 배열을 수정하므로 배열의 가시성에 대해 걱정할 필요가 없습니다. 동시에 각 요소는 Node 인스턴스입니다(Java 7의 각 요소는 HashEntry입니다). 해당 키 값과 해시 값은 최종적으로 수정되며 수정 후에는 변경될 수 없습니다. 해당 값과 다음 요소에 대한 참조는 휘발성에 의해 수정되며 가시성도 보장됩니다.
Size 작업: 각각의 대형 배열은 카운터를 유지 관리합니다. Put 메소드와 Remove 메소드는 모두 addCount 메소드를 통해 Map의 크기를 유지합니다. size 메소드는 addCount 메소드에 의해 유지되는 Map의 크기를 얻기 위해 sumCount를 사용합니다.ConcurrentHashMap에서 전역 카운터를 사용하는 대신 각 배열에 카운터를 포함하는 이유는 ConcurrentHashMap의 동시성을 고려하기 위함이라는 점에 유의하는 것이 중요합니다. 이런 방식으로 카운터를 업데이트해야 할 때 전체 ConcurrentHashMap을 잠가야 합니다개수는 휘발성이므로 모든 업데이트가 다른 스레드에 즉시 표시됩니다
관련 기사:
Java 프레임워크 Bootstrap, jQuery, SpringMVC, Hibernate 고성능 동시성
관련 동영상:
위 내용은 Java 동시성 알아보기: 잠금 최적화, ConcurrentHashMap, 잠금 분리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!