java8 concurrenthash_concurrenthashmap源码解析(Java7、Java8)

concurrenthashmap源码解析(Java1.7)

使用与获取全局信息的方法并不频繁的时候

01.在 ConcurrentHashMap中,不允许用 null作为键和值。

02.ConcurrentHashMap 使用分段锁(减少锁粒度)技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。

1.源码结构(从上往下)

重要字段

8208dff9d36df47ed8363c12e70ee885.png

字段

99fb417fc4a7b8c318b4d27fcdedad5d.png

ConcurrentHashMap列表条目。请注意,这从来没有导出

2c6edba6e576c6f9760fffd7a9f62f34.png

hash函数,段定义

746f860ebd823783e5bbf261993b8530.png

构造函数

cdb842b995dade7dd719febba7f697ac.png

常用的方法:

6fa46507472129455e7aa6b88a117998.png

迭代器支持

23ee92d1842a8df15e371aea8ca2c03e.png

序列化支持

9254fa4e0ea8842a628a34cd633bed45.png

2.数据结构

默认情况下分为16个段。

b6b7a351df9ada23f9ef4377d38a4e8a.pngstatic final class HashEntry {

final int hash;

final K key;

volatile V value;

volatile HashEntry next;

HashEntry(int hash, K key, V value, HashEntry next) {

this.hash = hash;

this.key = key;

this.value = value;

this.next = next;

}

/**

* Sets next field with volatile write semantics.  (See above

* about use of putOrderedObject.)

*/

final void setNext(HashEntry n) {

UNSAFE.putOrderedObject(this, nextOffset, n);

}

// Unsafe mechanics

static final sun.misc.Unsafe UNSAFE;

static final long nextOffset;

static {

try {

UNSAFE = sun.misc.Unsafe.getUnsafe();

Class k = HashEntry.class;

nextOffset = UNSAFE.objectFieldOffset

(k.getDeclaredField("next"));

} catch (Exception e) {

throw new Error(e);

}

}

}

static final class Segment extends ReentrantLock implements Serializable {

private static final long serialVersionUID = 2249069246763182397L;

static final int MAX_SCAN_RETRIES =

Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;

transient volatile HashEntry[] table;

transient int count;

transient int modCount;

transient int threshold;

final float loadFactor;

Segment(float lf, int threshold, HashEntry[] tab) {

this.loadFactor = lf;

this.threshold = threshold;

this.table = tab;

}

final V put(K key, int hash, V value, boolean onlyIfAbsent) {

HashEntry node = tryLock() ? null :

scanAndLockForPut(key, hash, value);

V oldValue;

try {

HashEntry[] tab = table;

int index = (tab.length - 1) & hash;

HashEntry first = entryAt(tab, index);

for (HashEntry e = first;;) {

if (e != null) {

K k;

if ((k = e.key) == key ||

(e.hash == hash && key.equals(k))) {

oldValue = e.value;

if (!onlyIfAbsent) {

e.value = value;

++modCount;

}

break;

}

e = e.next;

}

else {

if (node != null)

node.setNext(first);

else

node = new HashEntry(hash, key, value, first);

int c = count + 1;

if (c > threshold && tab.length 

rehash(node);

else

setEntryAt(tab, index, node);

++modCount;

count = c;

oldValue = null;

break;

}

}

} finally {

unlock();

}

return oldValue;

}

/**

* Doubles size of table and repacks entries, also adding the

* given node to new table

*/

@SuppressWarnings("unchecked")

private void rehash(HashEntry node) {

HashEntry[] oldTable = table;

int oldCapacity = oldTable.length;

int newCapacity = oldCapacity <

threshold = (int)(newCapacity * loadFactor);

HashEntry[] newTable =

(HashEntry[]) new HashEntry[newCapacity];

int sizeMask = newCapacity - 1;

for (int i = 0; i 

HashEntry e = oldTable[i];

if (e != null) {

HashEntry next = e.next;

int idx = e.hash & sizeMask;

if (next == null)   //  Single node on list

newTable[idx] = e;

else { // Reuse consecutive sequence at same slot

HashEntry lastRun = e;

int lastIdx = idx;

for (HashEntry last = next;

last != null;

last = last.next) {

int k = last.hash & sizeMask;

if (k != lastIdx) {

lastIdx = k;

lastRun = last;

}

}

newTable[lastIdx] = lastRun;

// Clone remaining nodes

for (HashEntry p = e; p != lastRun; p = p.next) {

V v = p.value;

int h = p.hash;

int k = h & sizeMask;

HashEntry n = newTable[k];

newTable[k] = new HashEntry(h, p.key, v, n);

}

}

}

}

int nodeIndex = node.hash & sizeMask; // add the new node

node.setNext(newTable[nodeIndex]);

newTable[nodeIndex] = node;

table = newTable;

}

private HashEntry scanAndLockForPut(K key, int hash, V value) {

HashEntry first = entryForHash(this, hash);

HashEntry e = first;

HashEntry node = null;

int retries = -1; // negative while locating node

while (!tryLock()) {

HashEntry f; // to recheck first below

if (retries 

if (e == null) {

if (node == null) // speculatively create node

node = new HashEntry(hash, key, value, null);

retries = 0;

}

else if (key.equals(e.key))

retries = 0;

else

e = e.next;

}

else if (++retries > MAX_SCAN_RETRIES) {

lock();

break;

}

else if ((retries & 1) == 0 &&

(f = entryForHash(this, hash)) != first) {

e = first = f; // re-traverse if entry changed

retries = -1;

}

}

return node;

}

private void scanAndLock(Object key, int hash) {

// similar to but simpler than scanAndLockForPut

HashEntry first = entryForHash(this, hash);

HashEntry e = first;

int retries = -1;

while (!tryLock()) {

HashEntry f;

if (retries 

if (e == null || key.equals(e.key))

retries = 0;

else

e = e.next;

}

else if (++retries > MAX_SCAN_RETRIES) {

lock();

break;

}

else if ((retries & 1) == 0 &&

(f = entryForHash(this, hash)) != first) {

e = first = f;

retries = -1;

}

}

}

final V remove(Object key, int hash, Object value) {

if (!tryLock())

scanAndLock(key, hash);

V oldValue = null;

try {

HashEntry[] tab = table;

int index = (tab.length - 1) & hash;

HashEntry e = entryAt(tab, index);

HashEntry pred = null;

while (e != null) {

K k;

HashEntry next = e.next;

if ((k = e.key) == key ||

(e.hash == hash && key.equals(k))) {

V v = e.value;

if (value == null || value == v || value.equals(v)) {

if (pred == null)

setEntryAt(tab, index, next);

else

pred.setNext(next);

++modCount;

--count;

oldValue = v;

}

break;

}

pred = e;

e = next;

}

} finally {

unlock();

}

return oldValue;

}

final boolean replace(K key, int hash, V oldValue, V newValue) {

if (!tryLock())

scanAndLock(key, hash);

boolean replaced = false;

try {

HashEntry e;

for (e = entryForHash(this, hash); e != null; e = e.next) {

K k;

if ((k = e.key) == key ||

(e.hash == hash && key.equals(k))) {

if (oldValue.equals(e.value)) {

e.value = newValue;

++modCount;

replaced = true;

}

break;

}

}

} finally {

unlock();

}

return replaced;

}

final V replace(K key, int hash, V value) {

if (!tryLock())

scanAndLock(key, hash);

V oldValue = null;

try {

HashEntry e;

for (e = entryForHash(this, hash); e != null; e = e.next) {

K k;

if ((k = e.key) == key ||

(e.hash == hash && key.equals(k))) {

oldValue = e.value;

e.value = value;

++modCount;

break;

}

}

} finally {

unlock();

}

return oldValue;

}

final void clear() {

lock();

try {

HashEntry[] tab = table;

for (int i = 0; i 

setEntryAt(tab, i, null);

++modCount;

count = 0;

} finally {

unlock();

}

}

}

3.put方法

流程:

728580862dd3d641432461d166af1d57.pngpublic V put(K key, V value) {

Segment s;

if (value == null)

throw new NullPointerException();

int hash = hash(key.hashCode());

int j = (hash >>> segmentShift) & segmentMask;

//上面两行用于获取段号

if ((s = (Segment)UNSAFE.getObject          // nonvolatile; recheck

(segments, (j <

s = ensureSegment(j);//得到段,将数据插入到段中

return s.put(key, hash, value, false);

}

static final class Segment extends ReentrantLock implements Serializable {

final V put(K key, int hash, V value, boolean onlyIfAbsent) {

HashEntry node = tryLock() ? null : //加锁

scanAndLockForPut(key, hash, value);

V oldValue;

try {

HashEntry[] tab = table;

int index = (tab.length - 1) & hash;

HashEntry first = entryAt(tab, index);

for (HashEntry e = first;;) {

if (e != null) {

K k;

if ((k = e.key) == key ||

(e.hash == hash && key.equals(k))) {

oldValue = e.value;

if (!onlyIfAbsent) {

e.value = value;

++modCount;

}

break;

}

e = e.next;

}

else {

if (node != null)

node.setNext(first);

else

node = new HashEntry(hash, key, value, first);

int c = count + 1;

if (c > threshold && tab.length 

rehash(node);

else

setEntryAt(tab, index, node);

++modCount;

count = c;

oldValue = null;

break;

}

}

} finally {

unlock(); //解锁

}

return oldValue;

}

}

@SuppressWarnings("unchecked")

static final  HashEntry entryAt(HashEntry[] tab, int i) {

return (tab == null) ? null :

(HashEntry) UNSAFE.getObjectVolatile

(tab, ((long)i <

}

static final  void setEntryAt(HashEntry[] tab, int i,

HashEntry e) {

UNSAFE.putOrderedObject(tab, ((long)i <

}

04.当系统需要取得全局锁,消耗资源就会比较多。比如size()方法:事实上会先使用无锁的方式求和,如果失败,会先获得所有段的锁再去求和。

899d054ac180141818d8a53ba1aafd4d.png

concurrenthashmap源码解析(Java1.8)

暂时先偷懒,参考别人的:http://blog.csdn.net/zly9923218/article/details/51420561

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值