ConcurrentHashMap 분석:예열(내부 작은 방법 분석)
9354 단어 ConcurrentHashMap입문 하 다
다음은 HashMap 멤버 들 의 방법 을 정식 적 으로 분석 하기 전에 내부 클래스 의 글자 방법 함 수 를 분석 합 니 다.
먼저 Concurrent HashMap 내부 클래스 Node 의 hash 멤버 속성 값 을 계산 하 는 방법
spread(int h
)을 살 펴 보 겠 습 니 다.
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;// spread(int h) ~
final K key;
volatile V val;
volatile Node<K,V> next;
Node(int hash, K key, V val, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.val = val;
this.next = next;
}
...
}
1.spread(int h)방법
/**
* Node hash : h hash
* eg:
* h --> 1100 0011 1010 0101 0001 1100 0001 1110
* (h >>> 16) --> 0000 0000 0000 0000 1100 0011 1010 0101
* (h ^ (h >>> 16)) --> 1100 0011 1010 0101 1101 1111 1011 1011
* :(h ^ (h >>> 16)) h 16 , hash , hash ~
* ------------------------------------------------------------------------------
* HASH_BITS --> 0111 1111 1111 1111 1111 1111 1111 1111
* (h ^ (h >>> 16)) --> 1100 0011 1010 0101 1101 1111 1011 1011
* (h ^ (h >>> 16)) & HASH_BITS --> 0100 0011 1010 0101 1101 1111 1011 1011
* : (h ^ (h >>> 16)) & HASH_BITS, hash
*/
static final int spread(int h) {
// hash ^ hash 16 , & HASH_BITS(0x7fffffff: 31 1)
return (h ^ (h >>> 16)) & HASH_BITS;
}
다음은 tabAt(Node2,tabAt 방법
/**
* tab(Node[]) i Node
* Node<K,V>[] tab: Node[]
* int i:
*/
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
// ((long)i << ASHIFT) + ABASE : ~
return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}
((long)i << ASHIFT) + ABASE
을 분석 할 때 먼저 이전 글 을 복습 합 니 다:Concurrent HashMap 소스 코드 분석01 구성원 속성,내부 유형,구조 방법 분석 에서 소개 한 일부 속성 필드 의 의미:
// Node class
Class<?> ak = Node[].class;
// U.arrayBaseOffset(ak): as Node[] ABASE
ABASE = U.arrayBaseOffset(ak);
// scale: , scale Node[]
int scale = U.arrayIndexScale(ak);// scale 2
// numberOfLeadingZeros(scale) scale, , , 0 :eg, 8 =>1000 numberOfLeadingZeros(8) 28, ? Integer 32 ,1000 4 , 32-4 0, 0 28
// 4 =>100 numberOfLeadingZeros(8) 29
// ASHIFT = 31 - Integer.numberOfLeadingZeros(4) = 2 ASHIFT ? :
// 5 Node[] ( ): scale ASHIFT = 2
// ABASE + (5 << ASHIFT) == ABASE + (5 << 2) == ABASE + 5 * scale( ), 5
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
위의 몇 가지 속성 필드 의 복습 소 개 를 통 해 얻 기 어렵 지 않 습 니 다.((long)i << ASHIFT) + ABASE
은 현재 Node[]
배열 에서 i 로 표 시 된 노드 대상 의 오프셋 주 소 를 얻 는 것 이다.그 다음 에
(Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE)
방법 을 통 해 Node[]
과 Node
두 개의 매개 변수 에 따라 i 로 표 시 된 Node 노드 대상 을 얻 었 다.이렇게 돌아 가 는 것 보다 못 하지만 오프셋 주소 에 따라 배열 요 소 를 찾 는 효율 이 높 습 니 다~
3,casTabAt 방법
/**
* CAS Node i , true, false
* Node<K,V>[] tab: Node[]
* int i:
* Node<K,V> c:
* Node<K,V> v:
*/
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
// Unsafe Node[] , :
// tab:Node[]
// ((long)i << ASHIFT) + ABASE: i
// c:
// v:
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
4.setTabAt 방법
/**
* i, Node[] :
* Node<K,V>[] tab: Node[]
* int i:
* Node<K,V> v:
*/
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
// ((long)i << ASHIFT) + ABASE: i
U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
}
5.resizeStamp 방법
/**
* table , , , :
*/
static final int resizeStamp(int n) {
// RESIZE_STAMP_BITS: 16, ,
return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
}
=
예 를 들 어 분석 해 보 자.우리 가 table 용량 이 16 라 이브 러 리 에서 32 까지 필요 할 때:
Integer.numberOfLeadingZeros(16)
을 얻 을 수 있 습 니 다.어떻게 얻 었 습 니까?numberOfLeadingZeros(n)
은 들 어 오 는 n
에 따라 현재 수 치 를 2 진법 으로 전환 한 후에 높 은 위치 에서 지위 까지 통 계 를 시작 하여 몇 개의 0 연속 이 한 조각 에 있 는 지 통계 했다.numberOfLeadingZeros(16
)의 결 과 는 27
이다.Integer
은 32 위,1 0000
이 5 위 를 차지 하기 때문에 앞 에 (32 - 5)
개 0,즉 가장 긴 0 개 수 는 27 개 이다.(1 << (RESIZE_STAMP_BITS - 1)):
중 RESIZE_STAMP_BITS
은 고정 치 16 으로 확장 과 관련 이 있 으 며 확장 을 계산 할 때 이 속성 치 에 따라 확장 표지 도장 을 생 성 한다.
// 16 32
16 -> 32
// A :
numberOfLeadingZeros(16) => 1 0000 => 27 => 0000 0000 0001 1011
// B :
(1 << (RESIZE_STAMP_BITS - 1)) => (1 << (16 - 1) => 1000 0000 0000 0000 => 32768
// A | B
Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1))
-----------------------------------------------------------------
0000 0000 0001 1011 ---> A
1000 0000 0000 0000 ---> B
------------------- ---> |
1000 0000 0001 1011 --->
6.tableSize For 방법
/**
* c, c , 2 , HashMap ~
* eg:c = 28 , 32
* c = 28 ==> n=27 => 0b 11011
*
* 11011 | 01101 => 11111 ---- n |= n >>> 1
* 11111 | 00111 => 11111 ---- n |= n >>> 2
* ....
* => 11111 + 1 = 100000 = 32
*/
private static final int tableSizeFor(int c) {
int n = c - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
7.구조 방법(복습)이전 글 에서 HashMap 의 구조 방법 을 복습 합 니 다.
//
public ConcurrentHashMap() {
}
//
public ConcurrentHashMap(int initialCapacity) {
if (initialCapacity < 0)
throw new IllegalArgumentException();
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
MAXIMUM_CAPACITY :
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
/**
* sizeCtl > 0
* table ,sizeCtl
*/
this.sizeCtl = cap;
}
// Map
public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
// sizeCtl
this.sizeCtl = DEFAULT_CAPACITY;
putAll(m);
}
// ,
public ConcurrentHashMap(int initialCapacity, float loadFactor) {
this(initialCapacity, loadFactor, 1);
}
// , ,
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
// initialCapacity concurrencyLevel
if (initialCapacity < concurrencyLevel)
// 。
// ,JDK1.8
initialCapacity = concurrencyLevel;
// , size
long size = (long)(1.0 + (long)initialCapacity / loadFactor);
// size
int cap = (size >= (long)MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY : tableSizeFor((int)size);
/**
* sizeCtl > 0
* table ,sizeCtl
*/
this.sizeCtl = cap;
}
8.총화예열 이 끝나 면 다음 글 은 맵 을 병행 하 는 데 중점 을 둔 곳 입 니 다.즉 put()기록 작업 원리~
저희 의 다른 콘 텐 츠 에 도 많은 관심 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
ConcurrentHashMap 분석:예열(내부 작은 방법 분석)다음은 HashMap 멤버 들 의 방법 을 정식 적 으로 분석 하기 전에 내부 클래스 의 글자 방법 함 수 를 분석 합 니 다. 먼저 Concurrent HashMap 내부 클래스 Node 의 hash 멤버 속성 값...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.