동시 읽기 및 쓰기 데이터 일관성 보장 (A) 자바 동시 용기

사업 개발 과정은, 사실, 사용자 트래픽 데이터, 따라서 핵심 작업의 발전 과정 오류없이 데이터 일관성을 유지하는 것입니다. 실제 장면을 복수의 사용자가 동시에 판독하고, 감소 된 충격 성능, 사용자 경험, 제어되지는 전복 동일한 데이터 (예를 들어, 스파이크)을 작성 동시성 제어를 추가한다.

어떻게 우아한 동시에 데이터를 제어? 필요성의 본질은 두 가지 문제를 해결하기 위해 :

  • 읽기 - 충돌 쓰기
  • 쓰기 - 충돌을 쓰기

의 자바 동시 용기 CopyOnWriteList 고전 ConcurrentHashMap의 방법이 두 가지 문제를 조정하는 방법을 살펴 보자

CopyOnWriteList

도식 흐름

문맹 퇴치 전략

CopyOnWrite 이름은 제안 복사 (copy-on-write) 전략을

로크 완료 출시 이후 다음 기록 제 플러스 ReentrantLock와 잠금 처리하고, 이후 상기 데이터를 참조 데이터의 사본으로 대체 한 후, 복사 변경 등을 확인하는 데이터의 복사본을 복사

에 따라 판독 처리에 대해서는 휘발성 제공 보장한다 의미 각 판독 최신 배열 참조 읽을 수

읽기 - 충돌 쓰기

물론, CopyOnWriteList 동시 읽기의 충돌을 해결하고 작성하는 별도의 읽기 및 쓰기 아이디어를 사용하여

읽기 및 쓰기 할 때 작업이 동시에 발생 :

  • 기록 동작이 참조 교체 완료되지 않은 경우, 서로 방해하지 않고 프로세스는 원래 배열 어레이 처리 동작의 복사본을 기록 읽기
  • 기록 동작이 기준 교체 완료되면, 판독되고, 동일한 어레이에 대한 참조를 조작 처리 물품

별도의 읽기 및 쓰기, 동시 읽기 및 쓰기 과정의 설계에 보이는, 읽기 최신 실시간 데이터, 이른바 약한 일관성을 보이지 않을 수 있습니다.

그것은 잠금 무료 지원 높은 동시 읽기의 읽기 작업을 허용, 강력한 일관성의 비용 때문이다

쓰기 - 충돌을 쓰기

여러 개의 동시 쓰기 작업이 첫 번째 잠금이 첫 번째 실행을 얻을 때 잠금이 해제 될 때까지 다른 스레드 만 차단 될 수 있습니다

간단하고 원유하지만 효과적인하지만, 상대적으로 가난한 동시성

ConcurrentHashMap의 (JDK7)

문맹 퇴치 전략

분할 로크를 사용하여 데이터의 동시 조작의 확률을 감소의 주요 아이디어

읽기 작업의 경우 :

  • 첫 번째 배열에 배치 세그먼트를 사용 UNSAFE.getObjectVolatile 원자 판독 의미 취득 세그먼트
  • HashEntry는 어레이 내에 위치 및 이용 UNSAFE.getObjectVolatile 원자 판독 의미론 HashEntry 취득
  • 그런 다음에 의존 최종 다음 포인터 목록을 순회 일정
  • 해당 찾기 휘발성 값을

쓰기 작업의 경우 :

  • 첫 번째 배열에 배치 세그먼트를 사용 UNSAFE.getObjectVolatile 원자 판독 의미 취득 세그먼트
  • 그리고 잠금을 시도 ReentrantLock와를
  • HashEntry는 어레이 내에 위치 및 이용 UNSAFE.getObjectVolatile HashEntry 취득 원 판독 헤드 의미론 노드리스트를
  • 목록 트래버스, 기존의 키가 발견 된 경우, 사용 UNSAFE.putOrderedObject 새 값을 쓰기 원자, 발견되지 않는 경우는, 활용하면서 새로운 노드가리스트의 선두에 삽입 만들 UNSAFE.putOrderedObject 원자 갱신 목록 헤드를
  • 그들은 잠금을 해제하기 위해 수행하는 경우

읽기 - 충돌 쓰기

데이터가 동시가 아닌 경우 읽고 서로 독립적으로 운영, 같은 세그먼트에 쓰기

같은 세그먼트에, ConcurrentHashMap의 독서를 많이 사용하고 작성하는 자바는 읽기 작업의 많은 더 록 없습니다 만들기, 충돌을 해결하는 경우 고급

읽기 및 쓰기 할 때 작업이 동시에 발생 :

  • 풋 키가 이미 직접 원래의 값을 업데이트 존재하는 경우,이 시간 읽기 작업은 고정하지 않고 휘발성을 보장하는 최신 값을 읽을 수 있습니다
  • 노드를 추가하거나, 노드를 삭제하는 경우, 상기 키가 존재하고, 따라서리스트를 복사해야 HashEntry 배열 요소를 업데이트하지 않는 경우, 다음의 각 PUT 포인터 (즉,리스트 번복 HashEntry을 지적 원래리스트 구조를 변경한다 그들은 읽기 작업은 새로운 업데이트 목록 전에 발생하면 안전하지 않은에서 제공하는 의미 보장, 업데이트를 완료 할 때 헤드 노드),이 시간은 여전히 ​​원래 목록, 아니 잠금을 얻을 수 있지만, 데이터가 오래

눈에 보이는, 지원 잠금 장치가없는 동시 읽기 또는 약 일관성

쓰기 - 충돌을 쓰기

동시 데이터 기록 동작은 서로 독립적으로 동작하며, 동일한 세그먼트에 있지 않다면

같은 세그먼트, 플러스 다중 스레드 또는 ReentrantLock와 잠금 원인을 차단하는 대기 때문에 만약

ConcurrentHashMap의 (JDK8)

문맹 퇴치 전략

JDK7 적은 세그먼트 락 부분이 층과 비교하면, 직접 이하 버킷로 지칭 노드 어레이 (목록 헤드 열)를 작동

읽기 작업에 의해 UNSAFE.getObjectVolatile 최신 원자 값을 의미 읽기

쓰기 작업의 경우, 게으른 방법의 사용은 버킷 수 단지 초기화없이 초기 기본을 결정하기 위해,로드합니다. 필요가 위치 인덱스의 값, 값은, 만약 그렇다면,에 의해 널인지 다음 버킷의 인덱스 넣을 때 UNSAFE.comepareAndSwapObject (CAS) 할당, null가 아닌 경우를, 다음, 동기화 잠금 장치를 추가하려면 해당 링크를 찾을 수 / 레드 - 블랙 트리 노드 값이 변경되면 잠금이 해제 된 후

읽기 - 충돌 쓰기

데이터가 동시에 판독되지 않으면 동일한 버킷 독립 비 간섭 쓰기

JDK7의 버전을 만들 훨씬 쉽게,하지만 여전히 많은 기능에 비해 같은 배럴에서 읽기 작업의 비 잠금 자바 기반 경우

읽기 및 쓰기 할 때 작업이 동시에 발생 :

  • 풋의 키가 이미, 다음 값을 업데이트 존재하는 경우에, 당신은 휘발성 보증의 최신 읽기 값을 얻을 수 있습니다
  • 풋 키가 존재하지 않을 경우, 새 노드를 만들거나 휘발성 다음 포인터가리스트의 마지막에 직접 삽입되어 원래 구조의 변화 (레드 - 블랙 트리가 일정 길이 이상이된다) 때 등 노드를 삭제 당신은 또한 최신 다음을 읽고 얻을 수있는 경우에 구조를 수정하는

너무 오래 쓰기 작업을 읽기 전에 발생으로, 휘발성 의미가 읽은 데이터가 최신 보장 할 수는 ConcurrentHashMap의의 JDK8 버전이 (강한과 일치라고 할 수있는 기본 능력 (/ PUT을 GET)에만 관심이 여기에, 약이있을 수 있습니다 이러한 작업의 확장과 같은 장면 누락,하지만 전 세계적으로 고정해야한다, 함께 배우고, 오류를 지적하시기 바랍니다 )

쓰기 - 충돌을 쓰기

데이터가 동시에 판독되지 않으면 동일한 버킷 독립 비 간섭 쓰기

같은 양동이 경우, 지적 쓰기는 다른 시나리오, CAS 또는 동기화 된 다른 전략을 채택

여러 쓰기 작업이 동시에 발생하면 버킷가 null의 경우 첫 번째 할당이 성공하면, CAS에이 동시 쓰기와 쓰기 작업을 처리, 쓰기 CAS 뒤에 스레드가 대기를 차단, 경쟁 동기화 잠금 실패

개요

왜 이러한 디자인 (개인 의견)

데이터 구조는 설계 데이터를 반드시 포함 저장, 데이터는 데이터 구조를 기반으로 모든 작업을했다

일반 아이디어는 전체 데이터 구조를 잠그는 것입니다,하지만 크게 성능에 영향을 미칩니다 잠금 장치가있다, 그래서 작업의 어떤 잠금이없는 수의 다음 작업은 찾아

작업은 두 가지 범주, 읽기 및 쓰기로 구분된다.

원래 데이터의 변경을 포함하기 때문에 통제되지 않은 확실히하는 방법을 제어하기 위해, 전복, 쓰기 봐?

기록 동작은 두 가지로 나눌 수 있으며, 하나는 않는 구조를 변경할 수

구조적 변화는 기록 할 내용에 관계없이 반드시 기초 된 원래 구조의 변화에 ​​의한 기본 어레이 또는 링크 된리스트의 직렬화 보장 원자 동작을 잠글 수 있고, 최적의 포인트는 시작과 동기화 된 다른 해시으로 최적화되는 로크 레벨 동기화 된 개선 된 잠금의 버전 1.8, ReentrantLock와 ConcurrentHashMap1.7 버전을 잠그는 잠금. 또는 데이터의 분산화와 같은 멀티 배럴 CopyOnWriteList보다 해시 기반 데이터 구조 등 concurrnethashmap 데이터 구조를 이용 분산

때문에 잠금 오버 헤드, 쓰기의 구조를 변경, 또는 작은 (배럴 확장 낮은 주파수)의 주파수를 변경하지 않는 CAS 좋은 생각, 너무 중대하다. 하지 CopyOnWriteList CAS 동시 기입을 제어하는 ​​이유는, 개인적 주된 이유 때문에 빈번한 구조적 변화 생각 같은 스토리지 기반 CAS 등 ActomicReferenceArray 용기 보일 수 있고, 구조의 변경 후에 생성 할 수 없다.

데이터를 보장하기 위해 오류 정정을 읽을 후 처리 비교적 쉽게

주요 고려 사항은 강하거나 약한 같은 문제와 일치하는 (쓰기 작업이 완료 될 때까지 기다립니다) 최신 실시간 데이터를 읽을 수 없습니다

강력한 일관성, 다음, 읽기, 경쟁 각 읽기 및 쓰기의 효율성에 영향을 미치는 같은 잠금 장치를, 쓰기, 쓰기 완료를 읽을 기다려야한다.

대부분의 경우에서, 데이터 일관성, 요구 사항을 작성하지 않은 요구 읽을 잘못 읽을 수 있지만 잘못된 결정. 데이터를 읽을 수있는이 순간에 완전히 변경되지 않은 경우 최종 마무리를 볼 수 읽을 수있는만큼 문제가되지 않는 오래된 데이터를 읽고

다행히, JMM (자바 메모리 모델) 휘발성 가시성 의미를 가지고, 우리는 경우가 잠겨되지 않도록 변화를보기 위해 데이터를 읽거나 쓸 수 있습니다. 다양한 안전하지 않은 패킷 직접 메모리 작업 상대적으로 높은 실적 가시성이 시맨틱 완료 할 수도 있습니다

읽기 작업의 경우, 최상의 데이터는 개조로 인한 문제에 대해 걱정하지 마십시오 동일한 데이터입니다. 유일한 상수는 일부 데이터는이 불변을 지원하려는 경우 여전히 변경 될 수 있습니다, 또는 변경의 빈도를 최소화하기 위해 변화, 다른 장소에서 프로세스의 일부를 변경해야, 소위 별도의 읽기 및 쓰기

수준에 의해 제한 순수한 개인의 이해보다 더 많은 아이디어가 반드시 정확하지 않습니다, 토론 가리키는 환영

추천 도서

동시 용기으로 CopyOnWriteArrayList

원칙과 소스 코드의 ConcurrentHashMap의 해석

고급 자바 (육) ConcurrentHashMap의 진화에서 자바 멀티 스레드 핵심 기술 참조

동시 컨테이너 ConcurrentHashMap의 (JDK 1.8 버전)

휘발성의 철저한 이해

추천

출처juejin.im/post/5d74ede4f265da0390055437