1,并发集合
一,concurrentHashMap!!!(超重点)
这里对concurrentHashMap的讲解分为jdk7和jdk8。
两个版本有了很大的变化
java7中着重讲解分段锁,java8中concurrentHashMap是基于数组加链表加红黑树实现的
1,java7中concurrentHashMap的实现
锁的粒度的减少有2钟方式,锁分解和锁分段。java7中concurrentHashMap就是基于锁分段实现的。它的实现使用了一个包含16个锁的数组,即Segment数组。默认每个锁具有散列桶的1/16.其中第N个桶由,其中,第N个散列桶由第(N mod 16)来保护。Segment数组长度即为并发数。
每个Segment元素存储的是HashEntry数组+链表。
put操作
会进行两次hash去定位Segment下的HashEntry的位置。然后接下来,我们注意一哈。。。首先我们看一下这个,如下
static class Segment<K,V> extends ReentrantLock implements Serializable {
它继承了锁的特性,当定位到位置时,会通过tryLock()尝试获取锁,如果获得就插入。否则自旋获取锁,超过指定次数就挂起,等待唤醒。
2,java8中concurrentHashMap的实现
上面讲过,java8中,concurrentHashMap是由红黑树+链表+数组实现的。
首先,来讲一下concurrentHashMap中的几个重要内部类
Node,TreeNode,TreeBin
Node
Node是存储结构的基本单元,实现了Map.Entry接口。
源码如下。
static class Node<K,V> implements Map.Entry<K,V> {
//链表的数据结构
final int hash;
final K key;
//val和next都会在扩容时发生变化,所以加上volatile来保持可见性和禁止重排序
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; }
//不允许更新value
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)));
}
//用于map中的get()方法,子类重写
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;
}
}
很容易看出Node就是一个存储的链表,但只允许进行查找。其中有点需要注意:它对value和next属性设置了volatile同步锁。
TreeNode
TreeNode继承于Node,不同的是它是二叉树的存储结构,并非链表。
用于在红黑树中存储数据。
conCurrentHashMap中链表节点数大于8时会转换成红黑树结构。此时,TreeNode就会代替Node来存储数据,源码如下
static final class TreeNode<K,V> extends Node<K,V> {
//树形结构的属性定义
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red; //标志红黑树的红节点
TreeNode(int hash, K key, V val, Node<K,V> next,
TreeNode<K,V> parent) {
super(hash, key, val, next);
this.parent = parent;
}
Node<K,V> find(int h, Object k) {
return findTreeNode(h, k, null);
}
//根据key查找 从根节点开始找出相应的TreeNode,
final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
if (k != null) {
TreeNode<K,V> p = this;
do {
int ph, dir; K pk; TreeNode<K,V> q;
TreeNode<K,V> pl = p.left, pr = p.right;
if ((ph = p.hash) > h)
p = pl;
else if (ph < h)
p = pr;
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
return p;
else if (pl == null)
p = pr;
else if (pr == null)
p = pl;
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
else if ((q = pr.findTreeNode(h, k, kc)) != null)
return q;
else
p = pl;
} while (p != null);
}
return null;
}
}
TreeBin
上面说过,TreeBin用来包装TreeNode。它提供了转换红黑树的一些条件和锁的控制。它还带了读写锁。部分源码如下
static final class TreeBin<K,V> extends Node<K,V> {
//指向TreeNode列表和根节点
TreeNode<K,V> root;
volatile TreeNod