ConcurrentHashMap锁分段机制
1 HashTable的弊端
传统的HashTable会将哈希表整体锁住,导致原本的并行操作转换成串行化操作,提高了数据的一致性,但是性能很低,由于使用锁的机制,会导致复合操作线程不安全的问题,如:“若不存在则添加”。这种复合操作需要两步操作,首先需要判断是否存在,之后进行添加操作,两个方法均存在锁机制,如果判断是否存在的方法执行权被剥夺,则会产生严重的线程安全问题
2 ConcurrentHashMap锁分段机制
-
Java5.0在
java.util.concurrent
包中提供了多种并发容器类来改进同步容器的性能。 -
ConcurrentHashMap
同步容器类是Java5增加的一个线程安全的哈希表。对与多线程的操作,介于HashMap
与Hashtable
之间。内部采用“锁分段”机制替代Hashtable
的独占锁。进而提高性能。 -
此包还提供了设计用于多线程上下文中的
Collection
实现:ConcurrentHashMap
、ConcurrentSkipListMap
、ConcurrentSkipListSet
、CopyOnWriteArrayLis
t和CopyOnWriteArraySet
。- 当期望许多线程访问一个给定
collection
时,ConcurrentHashMap
通常优于同步的HashMap
,ConcurrentSkipListMap
通常优于同步的TreeMap
。 - 当期望的读数和遍历远远大于列表的更新数时,
CopyOnWriteArrayList
优于同步的ArrayList
。
- 当期望许多线程访问一个给定
-
并发读写问题
package JUC;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ConcurrentHashMapTest {
public static void main(String[] args) {
ThreadTest3 test3 = new ThreadTest3();
for (int i = 0; i < 10; i++) {
new Thread(test3).start();
// 报错:java.util.ConcurrentModificationException
// 原因:在线程中,既从list中读取值,又向list中写入值
}
}
}
class ThreadTest3 implements Runnable {
private static List<String> list = new ArrayList<String>();
static {
list.add("aa");
list.add("bb");
list.add("cc");
}
@Override
public void run() {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
list.add("ee");
}
}
}
- 解决办法:使用
CopyOnWriteArrayList
(写入并复制:每次写入时先进行复制,添加操作时效率低,适合多迭代的操作),用法与普通的List
相同
package JUC;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class ConcurrentHashMapTest {
public static void main(String[] args) {
ThreadTest4 test4 = new ThreadTest4();
for (int i = 0; i < 10; i++) {
new Thread(test4).start();
}
}
}
class ThreadTest4 implements Runnable {
private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
static {
list.add("aa");
list.add("bb");
list.add("cc");
}
@Override
public void run() {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
list.add("ee");
}
}
}