Skip to content

Commit 8dda86c

Browse files
ConcurrentCollection
1 parent 55a26e6 commit 8dda86c

17 files changed

+764
-0
lines changed

Collection/Collection.iml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="JAVA_MODULE" version="4">
3+
<component name="NewModuleRootManager" inherit-compiler-output="true">
4+
<exclude-output />
5+
<content url="file://$MODULE_DIR$">
6+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
7+
</content>
8+
<orderEntry type="inheritedJdk" />
9+
<orderEntry type="sourceFolder" forTests="false" />
10+
</component>
11+
</module>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* 并发容器总结
3+
*
4+
* @Author: zzStar
5+
* @Date: 10-12-2020 13:39
6+
*/
7+
public class CollectionSummary {
8+
/**
9+
* java.util.concurrent包提供的容器,分为3类:
10+
* Concurrent*、CopyOnWrite*、Blocking*
11+
*
12+
* Concurrent*的特点大部分通过CAS实现并发,而CopyOnWrite*则是通过复制一份原数据来实现
13+
* Blocking*是通过AQS实现
14+
*/
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package concurrenthashmap;
2+
3+
/**
4+
* 并发容器概览
5+
*
6+
* @Author: zzStar
7+
* @Date: 10-11-2020 19:57
8+
*/
9+
public class CollectionSummary {
10+
11+
/**
12+
* ConcurrentHashMap 线程安全的HashMap
13+
* CopyOnWriteArrayList 线程安全的List
14+
*
15+
* BlockingQueue 接口,阻塞队列,适合用于作为数据共享的通道
16+
* ConcurrentLinkedQueue 高效的非阻塞并发队列,使用链表实现,可看作线程安全的LinkedList
17+
*/
18+
19+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package concurrenthashmap;
2+
3+
import java.util.concurrent.ConcurrentHashMap;
4+
5+
/**
6+
* jdk1.8后,结构和1.8后的hashmap类似
7+
* <p>
8+
* 1.7是16个Segment,每个Segment里面是类似hashmap的结构
9+
* 1.8是链表+红黑树
10+
* <p>
11+
* ConcurrentHashMap源码浅析
12+
*
13+
* @Author: zzStar
14+
* @Date: 10-11-2020 20:22
15+
*/
16+
public class ConcurrentHashMapAnalysis {
17+
}
18+
19+
/*
20+
public V get(Object key) {
21+
ConcurrentHashMap.Node<K,V>[] tab; ConcurrentHashMap.Node<K,V> e, p; int n, eh; K ek;
22+
//得到hash值
23+
int h = spread(key.hashCode());
24+
if ((tab = table) != null && (n = tab.length) > 0 &&
25+
(e = tabAt(tab, (n - 1) & h)) != null) {
26+
if ((eh = e.hash) == h) {
27+
//槽点和key符合则直接返回value
28+
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
29+
return e.val;
30+
}
31+
//负数说明,得到的是一个红黑树结点或者为转移结点,调用find方法取值
32+
else if (eh < 0)
33+
return (p = e.find(h, key)) != null ? p.val : null;
34+
//若均不是,则遍历链表取值
35+
while ((e = e.next) != null) {
36+
if (e.hash == h &&
37+
((ek = e.key) == key || (ek != null && key.equals(ek))))
38+
return e.val;
39+
}
40+
}
41+
return null;
42+
}
43+
*/
44+
45+
46+
/*
47+
final V putVal(K key, V value, boolean onlyIfAbsent) {
48+
//判断是否为空,不允许为空
49+
if (key == null || value == null) throw new NullPointerException();
50+
//计算hash值
51+
int hash = spread(key.hashCode());
52+
int binCount = 0;
53+
//根据对应位置节点的类型来赋值,或者helpTransfer,或者增长链表,或者给红黑树增加节点
54+
for (ConcurrentHashMap.Node<K,V>[] tab = table;;) {
55+
ConcurrentHashMap.Node<K,V> f; int n, i, fh; K fk; V fv;
56+
if (tab == null || (n = tab.length) == 0)
57+
//初始化tab
58+
tab = initTable();
59+
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
60+
//cas操作,直接放进去
61+
if (casTabAt(tab, i, null, new ConcurrentHashMap.Node<K,V>(hash, key, value)))
62+
break; // no lock when adding to empty bin
63+
}
64+
//MOVED转移结点,说明槽点正在扩容,帮助进行
65+
else if ((fh = f.hash) == MOVED)
66+
tab = helpTransfer(tab, f);
67+
else if (onlyIfAbsent // check first node without acquiring lock
68+
&& fh == hash
69+
&& ((fk = f.key) == key || (fk != null && key.equals(fk)))
70+
&& (fv = f.val) != null)
71+
return fv;
72+
else {
73+
V oldVal = null;
74+
synchronized (f) {
75+
if (tabAt(tab, i) == f) {
76+
if (fh >= 0) {
77+
binCount = 1;
78+
for (ConcurrentHashMap.Node<K,V> e = f;; ++binCount) {
79+
K ek;
80+
//判断当前是否存在这个key
81+
if (e.hash == hash &&
82+
((ek = e.key) == key ||
83+
(ek != null && key.equals(ek)))) {
84+
oldVal = e.val;
85+
if (!onlyIfAbsent)
86+
e.val = value;
87+
break;
88+
}
89+
//不存在就新创建一个结点
90+
ConcurrentHashMap.Node<K,V> pred = e;
91+
if ((e = e.next) == null) {
92+
pred.next = new ConcurrentHashMap.Node<K,V>(hash, key, value);
93+
break;
94+
}
95+
}
96+
}
97+
//红黑树
98+
else if (f instanceof ConcurrentHashMap.TreeBin) {
99+
ConcurrentHashMap.Node<K,V> p;
100+
binCount = 2;
101+
if ((p = ((ConcurrentHashMap.TreeBin<K,V>)f).putTreeVal(hash, key,
102+
value)) != null) {
103+
oldVal = p.val;
104+
if (!onlyIfAbsent)
105+
p.val = value;
106+
}
107+
}
108+
else if (f instanceof ConcurrentHashMap.ReservationNode)
109+
throw new IllegalStateException("Recursive update");
110+
}
111+
}
112+
//完成添加后,判断是否需要将链表转为树
113+
if (binCount != 0) {
114+
//大于阈值8,则转为树
115+
if (binCount >= TREEIFY_THRESHOLD)
116+
//treeifyBin还要满足最低容量条件64
117+
treeifyBin(tab, i);
118+
if (oldVal != null)
119+
return oldVal;
120+
break;
121+
}
122+
}
123+
}
124+
addCount(1L, binCount);
125+
return null;
126+
}
127+
*/
128+
129+
/**
130+
* 为什么超过8要转为红黑树?
131+
* 1.默认是链表,红黑树每个节点占用的空间是链表的2倍
132+
* 2.经过泊松分布,hash冲突到达8的时候概率小于千万分之1 (0.00000006),正常情况下,链表的长度不会达到8,但为保证极端情况下,仍有较高的查询效率,转为红黑树
133+
*/
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package concurrenthashmap;
2+
3+
import java.util.HashMap;
4+
5+
/**
6+
* 演示hashmap在多线程情况下造成死循环的情况 导致循环链表,造成CPU100%,出现OOM
7+
* 注意:仅在JDK7及以前存在!
8+
* hashmap定位就不是高并发
9+
*
10+
* hashmap非线程安全,但只读的并发是安全的
11+
*
12+
* @Author: zzStar
13+
* @Date: 10-12-2020 09:02
14+
*/
15+
public class HashMapEndLessLoop {
16+
17+
//扩容的时候问题出现,当内容超过4,触发扩容机制
18+
private static HashMap<Integer, String> map = new HashMap<>(2, 1.5f);
19+
20+
public static void main(String[] args) {
21+
map.put(5, "c");
22+
map.put(7, "b");
23+
map.put(3, "a");
24+
new Thread(() -> {
25+
map.put(15, "d");
26+
System.out.println(map);
27+
}, "thread1").start();
28+
29+
new Thread(() -> {
30+
map.put(1, "e");
31+
System.out.println(map);
32+
}, "thread2").start();
33+
34+
}
35+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package concurrenthashmap;
2+
3+
import java.util.Hashtable;
4+
5+
/**
6+
* 同样大量在方法上加上synchronized,并发性能差
7+
*
8+
* @Author: zzStar
9+
* @Date: 10-11-2020 20:10
10+
*/
11+
public class HashtableDemo {
12+
public static void main(String[] args) {
13+
Hashtable<String, String> hashtable = new Hashtable<>();
14+
hashtable.put("I love Java", "forever");
15+
String s = hashtable.get("I love Java");
16+
System.out.println("s = " + s);
17+
}
18+
}
19+
20+
/*
21+
public synchronized V get(Object key) {
22+
Hashtable.Entry<?,?> tab[] = table;
23+
int hash = key.hashCode();
24+
int index = (hash & 0x7FFFFFFF) % tab.length;
25+
for (Hashtable.Entry<?,?> e = tab[index]; e != null ; e = e.next) {
26+
if ((e.hash == hash) && e.key.equals(key)) {
27+
return (V)e.value;
28+
}
29+
}
30+
return null;
31+
}
32+
*/
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package concurrenthashmap;
2+
3+
import java.util.concurrent.ConcurrentHashMap;
4+
5+
/**
6+
* 组合操作并不保证ConcurrentHashMap的线程安全
7+
*
8+
* @Author: zzStar
9+
* @Date: 10-12-2020 10:08
10+
*/
11+
public class OptionNotSafe implements Runnable {
12+
private static ConcurrentHashMap<String, Integer> scores = new ConcurrentHashMap<String, Integer>();
13+
14+
public static void main(String[] args) throws InterruptedException {
15+
scores.put("zzStar", 0);
16+
Thread thread1 = new Thread(new OptionNotSafe());
17+
Thread thread2 = new Thread(new OptionNotSafe());
18+
thread1.start();
19+
thread2.start();
20+
thread1.join();
21+
thread2.join();
22+
System.out.println(scores);
23+
}
24+
25+
@Override
26+
public void run() {
27+
for (int i = 0; i < 1000; i++) {
28+
/*
29+
//同步的类锁实现线程安全
30+
synchronized (concurrenthashmap.OptionNotSafe.class) {
31+
Integer score = scores.get("zzStar");
32+
int newScore = score + 1;
33+
scores.put("zzStar", newScore);
34+
}
35+
*/
36+
while (true) {
37+
Integer score = scores.get("zzStar");
38+
int newScore = score + 1;
39+
//运用replace先检查值是否为原值,是则替换,线程安全
40+
boolean replace = scores.replace("zzStar", score, newScore);
41+
if (replace) {
42+
break;
43+
}
44+
}
45+
46+
}
47+
}
48+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package concurrenthashmap;
2+
3+
import java.util.*;
4+
import java.util.ArrayList;
5+
6+
/**
7+
* Collections.synchronizedList同样性能不高
8+
*
9+
* @Author: zzStar
10+
* @Date: 10-11-2020 20:16
11+
*/
12+
public class SynList {
13+
public static void main(String[] args) {
14+
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
15+
list.add(5);
16+
System.out.println(list.get(0));
17+
}
18+
}
19+
20+
/*
21+
public static <T> List<T> synchronizedList(List<T> list) {
22+
return (list instanceof RandomAccess ?
23+
new Collections.SynchronizedRandomAccessList<>(list) :
24+
new Collections.SynchronizedList<>(list));
25+
}
26+
*/
27+
28+
/*
29+
public class ArrayList<E> extends AbstractList<E>
30+
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
31+
*/
32+
33+
/*
34+
public E get(int index) {
35+
synchronized (mutex) {return list.get(index);}
36+
}
37+
public E set(int index, E element) {
38+
synchronized (mutex) {return list.set(index, element);}
39+
}
40+
public void add(int index, E element) {
41+
synchronized (mutex) {list.add(index, element);}
42+
}
43+
public E remove(int index) {
44+
synchronized (mutex) {return list.remove(index);}
45+
}
46+
*/
47+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package concurrenthashmap;
2+
3+
import java.util.Vector;
4+
5+
/**
6+
* Vector源码
7+
* 大量的synchronized导致性能缺失
8+
*
9+
* @Author: zzStar
10+
* @Date: 10-11-2020 20:05
11+
*/
12+
public class VectorDemo {
13+
public static void main(String[] args) {
14+
Vector<String> vector = new Vector<>();
15+
vector.add("Vector");
16+
System.out.println(vector.get(0));
17+
}
18+
}
19+
20+
//下面是源码
21+
/*
22+
public synchronized E get(int index) {
23+
if (index >= elementCount)
24+
throw new ArrayIndexOutOfBoundsException(index);
25+
26+
return elementData(index);
27+
}
28+
*/

0 commit comments

Comments
 (0)