ConcurrentHashMap锁分段机制
1. 关于HashMap和HashTable
HashMap:线程不安全
HashTable:
-
效率低:操作时锁整个表
-
复合操作会带来安全问题
// table.contains()和table.put()分别都是加了锁的,但是像下述复合操作,一个线程判断完之后CPU可能被其他线程抢夺,带来安全问题 if(!table.contains(element)){ table.put(element) }
2. 锁分段机制
ConcurrentHashMap锁分段机制是在JDK 1.7的时候用的,JDK1.8有了很大的改变
类型 | JDK1.7 | JDK1.8 |
---|---|---|
数据结构 | Segment分段锁 | 数组+链表+红黑树 |
线程安全机制 | Segment的分段锁机制 | CAS+Synchorized机制 |
锁的粒度 | 每段Segment加锁,粒度大 | 每个Node元素加锁,粒度更细 |
遍历时间复杂度 | O(n) | O(logN) |
介绍下JDK 1.7的锁分段机制
3. 多线程Collection
HashMap =》 ConcurrentHashMap
TreeMap =》 ConcurrentSkipListMap
ArrayList =》 CopyOnWriteArrayList
Collections.synchronizedXXX()的工作原理:为XXX的每个操作都包上一层synchronized
Collections.synchronizedXXX()存在的问题
package com.atguigu.juc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class TestCopyAndWriteArrayList {
public static void main(String[] args) {
HelloThread helloThread = new HelloThread();
for (int i = 0; i < 10; i++) {
new Thread(helloThread).start();
}
}
}
class HelloThread implements Runnable{
private static List<String> list = Collections.synchronizedList(new ArrayList<String>());
static {
list.add("AA");
list.add("BB");
list.add("CC");
}
@Override
public void run() {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
// 边读边写
System.out.println(iterator.next());
list.add("AA");
}
}
}
出现上述问题的原因是迭代读取的数据源和写入的数据源是同一个
使用CopyOnWriteArrayList
可解决上述问题
private static List<String> list = Collections.synchronizedList(new ArrayList<String>());
替换为
private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
即可
注:CopyOnWriteXXX添加操作多时,效率低,因为每次添加时都会进行复制,开销非常的大。并发迭代操作多时可以选择