Java 集合及映射
Java中线性及非线性数据结构的工具类非常全面完整,以下:
-
Collection
-
List
- ArrayList - 数组式
- LinkedList - 链式
- Vector - 数组式线程安全
-
Set
- HashSet - 散列表
- TreeSet - 红黑树
-
-
Map
- HashMap - 散列表 + 数组式 + 链式
- TreeMap - 散列表 + 红黑树
- Hashtable - 散列表线程安全
- WeakHashMap - 弱引用配合GC达到防止内存溢出的功能
- ConcurrentHashMap - 散列表 + 锁分段取代Hashtable
-
Queue
- LinkedBlockingQueue - 链式队列
- ArrayBlockingQueue - 数组式队列
- CachedBlockingQueue - 缓冲式队列,长度无限制
- ConcurrentLinkedQueue - 链式队列线程安全
-
Tip:
- 其中Vector可被ConcurrentLinkedQueue取代,ConcurrentLinkedQueue采用链式队列,在同步时用volatile的乐观锁,在缓冲总线将数据同步,比synchronized方法要更加轻量和高效。当然,Vector数组式的数据结构终究不能被队列替代,例如要往集合中间部分添加元素,ConcurrentLinkedQueue是做不到的,也正因为它删除了部分数据操作功能,ConcurrentLinkedQueue才能使用volatile。
- Hashtable可被ConcurrentHashMap取代,ConcurrentHashMap采用散列表 + 锁分段的方法,将Map分割为多个段落,并用多个锁同步不同的段落,那么在数据量较大时效率会有很大提升。
- WeakHashMap 通过若引用标记配合GC在Root搜索时可分段搜索,达到可部分回收的能力。
- LinkedBlockingQueue、ArrayBlockingQueue、CachedBlockingQueue3种queue被线程池作为等待队列,LinkedBlockingQueue的长度可伸缩,ArrayBlockingQueue的长度固定,CachedBlockingQueue的长度可无限增长,为线程池带来了本质上的差异。
接下来我们对ConcurrentHashMap和Hashtable的性能做个对比
public class BaseMap {
public static void main(String[] args) {
ExecutorService pool2 = Executors.newFixedThreadPool(20);
ConcurrentHashMap<String,String> currentHashMap = new ConcurrentHashMap<String,String>();
System.out.println("start time 1 -> "+new Date().getTime());
for (int i = 0; i < 1000000; i++) {
pool2.submit(()->{
currentHashMap.put("test", "test");
});
}
System.out.println("end time 1 -> "+new Date().getTime());
ExecutorService pool = Executors.newFixedThreadPool(20);
System.out.println("start time 3 -> "+new Date().getTime());
Hashtable<String,String> hashMap = new Hashtable<String,String>();
for (int i = 0; i < 1000000; i++) {
pool.submit(()->{
hashMap.put("test", "test");
});
}
System.out.println("end time 3 -> "+new Date().getTime());
}
}
HashMap比ConcurrentHashMap的更新速度要慢1.5倍以上
读者可以用同样的方式测试其它组件的性能差异