ConcurrentHashMap
- Java 5.0 在java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能。
- ConcurrentHashMap 同步容器类是Java 5 增加的一个线程安全的哈希表。对与多线程的操作,介于HashMap 与Hashtable 之间。内部采用“锁分段”机制替代Hashtable 的独占锁。进而提高性能。
- 此包还提供了设计用于多线程上下文中的Collection 实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和CopyOnWriteArraySet。当期望许多线程访问一个给定collection 时,ConcurrentHashMap 通常优于同步的HashMap,ConcurrentSkipListMap 通常优于同步的TreeMap。当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrayList 优于同步的ArrayList。
HashMap与Hashtable 的底层是一样的,Hashtable是线程安全的,hashtable会给整个Hash表加上锁,导致运行效率非常低。使用Hashtable进行操作时,并没有达到并行的目的,相当于并行转串行。
Hashtable还存在复合操作: 复合操作也是线程不安全的
"若不存在则添加"
"若存在则删除"
if(table.contains()){
//table.put()
}
ConcurrentHashMap 采用 "锁分段" 机制
ConcurrentHashMap 中有一个级别 叫 ConcurrentLevel,默认级别为16
即分为16个段,默认有16个段(Segment),每个段中有一个独立hash表,默认Hash表长度为16
每个段都是一个独立的锁,这就意味着线程多个线程访问不同的段是互不干扰的,达到并行的目的
CopyOnWriteArrayList
package com.java.juc; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TestCopyOnWriteArrayList { public static void main(String[] args) { HelloThread ht = new HelloThread(); for(int i = 0;i<10;i++){ new Thread(ht).start(); } } } class HelloThread implements Runnable{ private static List<String> list = new ArrayList<>(); static{ list.add("AA"); list.add("BB"); list.add("CC"); } public void run() { Iterator<String> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } list.add("DD"); } }
会出现如下问题:
Exception in thread "Thread-9" Exception in thread "Thread-7" Exception in thread "Thread-5" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33) at java.lang.Thread.run(Unknown Source) java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33) at java.lang.Thread.run(Unknown Source) java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33) at java.lang.Thread.run(Unknown Source) Exception in thread "Thread-4" Exception in thread "Thread-0" Exception in thread "Thread-1" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33) at java.lang.Thread.run(Unknown Source)
可以使用 CopyOnWriteArrayList 解决问题:
package com.java.juc; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class TestCopyOnWriteArrayList { public static void main(String[] args) { HelloThread ht = new HelloThread(); for(int i = 0;i<10;i++){ new Thread(ht).start(); } } } class HelloThread implements Runnable{ // private static List<String> list = new ArrayList<>(); private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); static{ list.add("AA"); list.add("BB"); list.add("CC"); } public void run() { Iterator<String> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } list.add("DD"); } }
注意:添加操作多时,效率低,因为每次添加时都会进行复制,开销非常大。并发迭代操作多时可以选择。