ConcurrentHashMap学习笔记(Java8)
来源:互联网 发布:sql merge into 编辑:程序博客网 时间:2024/05/17 23:29
ConcurrentHashMap是Concurrent包里提供的一个解决并发问题的HashMap,试着从源代码来认识这个类
首先我们来看一下ConcurrentHashMap中两个重要的内部类:Node(节点)和Segment(桶)
Node的源代码如下
static class Node<K,V> implements Map.Entry<K,V> { final int hash; 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; } public final K getKey() { return key; } public final V getValue() { return val; } public final int hashCode() { return key.hashCode() ^ val.hashCode(); } public final String toString(){ return key + "=" + val; } public final V setValue(V value) { throw new UnsupportedOperationException(); } public final boolean equals(Object o) { Object k, v, u; Map.Entry<?,?> e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry<?,?>)o).getKey()) != null && (v = e.getValue()) != null && (k == key || k.equals(key)) && (v == (u = val) || v.equals(u))); } /** * Virtualized support for map.get(); overridden in subclasses. */ Node<K,V> find(int h, Object k) { Node<K,V> e = this; if (k != null) { do { K ek; if (e.hash == h && ((ek = e.key) == k || (ek != null && k.equals(ek)))) return e; } while ((e = e.next) != null); } return null; } }
其中构造函数中需要对四个成员变量进行初期化:Key,Value,hash(散列值),next(下一个节点)
需要注意的几个方法是
setValue()时直接抛出以一个异常?(UnsupportedOperationException)
hashCode()返回该节点的散列值,该散列值为key与value的散列值按位与算出
equalsIO方法需要判断key值相同且value值相同
find()方法根据散列值及key值,遍历所有节点值取得对象节点,没有取得相应节点时返回null
其中setValue()与Hashmap不同,find()为新增方法,另外,java8中HashMap引入了树结构,在ConcurrentHashMap中尚未有反映
接下来看Segment的源代码。
static class Segment<K,V> extends ReentrantLock implements Serializable { private static final long serialVersionUID = 2249069246763182397L; final float loadFactor; Segment(float lf) { this.loadFactor = lf; } }
作为ConcurrentHashMap重要的内部类,Segment的代码只有三行,需要注意的是继承了ReentrantLock方法,可以认为Segment也是一种锁结构,构造函数中初始化了负载因子。
Segment的代码在Java8中极大地简化。相对应的是Java8版本的ConcurrentHashMap中出现了TreeNode和TreeBin结构。应该是利用红黑树进行了数据存储。仅红黑树这一节就足够写一篇很长的笔记了,我们先把它放在一边,先看核心的get/set机能
/** * Maps the specified key to the specified value in this table. * Neither the key nor the value can be null. * * <p>The value can be retrieved by calling the {@code get} method * with a key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with {@code key}, or * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key or value is null */ public V put(K key, V value) { return putVal(key, value, false); } /** Implementation for put and putIfAbsent */ final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); int hash = spread(key.hashCode()); int binCount = 0; for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; if (tab == null || (n = tab.length) == 0) tab = initTable(); else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { V oldVal = null; synchronized (f) { if (tabAt(tab, i) == f) { if (fh >= 0) { binCount = 1; for (Node<K,V> e = f;; ++binCount) { K ek; if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { oldVal = e.val; if (!onlyIfAbsent) e.val = value; break; } Node<K,V> pred = e; if ((e = e.next) == null) { pred.next = new Node<K,V>(hash, key, value, null); break; } } } else if (f instanceof TreeBin) { Node<K,V> p; binCount = 2; if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } if (binCount != 0) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; break; } } } addCount(1L, binCount); return null; }
ConcurrentHashMap与HashMap的一个区别就是,ConcurrentHashMap不允许Key值为null,为null的时候会直接抛出一个空指针异常
未完待续
- ConcurrentHashMap学习笔记(Java8)
- java8 ConcurrentHashMap
- ConcurrentHashMap--Java8
- Java8-ConcurrentHashMap
- ConcurrentHashMap学习笔记一
- ConcurrentHashMap学习笔记
- java8 Stream学习笔记
- java8 stream学习笔记
- JAVA8学习笔记-function
- java8 注解学习笔记
- Java8学习笔记
- JAVA8学习笔记-Function
- Java8 学习笔记之一
- Java8学习笔记
- Java8学习笔记
- Java并发学习(十九)-Java8中ConcurrentHashMap分析
- ConcurrentHashMap源码分析--Java8
- ConcurrentHashMap源码分析--Java8
- 数据分析与数据挖掘在常规工作中的应用——数据异常值
- 四旋翼飞行器之PID参数整定
- Ubuntu右键打开一个终端脚本
- C#多线程同步(六)【CountdownEvent】
- Android Fragment 小结(1)
- ConcurrentHashMap学习笔记(Java8)
- Deep Image Homography Estimation 个人解读
- android binder机制 阅读笔记
- 承接上一篇:说说评论弹出editext,计算软键盘高度,使listview,recyclerview上滑指定高度
- 4.struts2_4_配置文件详解
- 方法
- 欢迎使用CSDN-markdown编辑器
- MyBatis 菜鸟教程 1 环境配置
- 集合框架_HashSet保证元素唯一性的源码解析