赞
踩
Vector 与 ArrayList 类似,是长度可变的数组,与 ArrayList 不同的是,Vector 是线程安全的,它给几乎所有的 public 方法都加上了 synchronized 关键字。由于加锁导致性能降低,在不需要并发访问同一对象时,这种强制性的同步机制就显得多余,所以现在 Vector 已被弃用。
HashTable 和 HashMap 类似,不同点是 HashTable 是线程安全的,但它给几乎所有 public 方法都加上了 synchronized 关键字,还有一个不同点是 HashTable 的K,V都不能是 null,但 HashMap 可以,所以它现在也因为性能原因被启用了。
Vector 和 HashTable 被弃用后,他们被 ArrayList 和 HashMap 代替,但他们是线程不安全的,所以 Colletions 工具类中提供了相应的包装方法把他们包装成线程安全的集合。
List<E> synchronizedList = Collections.synchronizedList(new ArrayList<>());
Map<Object, Object> synchronizedMap = Collections.synchronizedMap(new HashMap<>(16));
Set<Object> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
......
Collections 针对每种集合都声明了一个线程安全的包装类,在原集合的基础上添加了锁对象,集合中的每个方法都通过这个锁对象实现同步。
ConcurrentHashMap 和 HashTable 都是线程安全的集合,他们的不同主要是加锁粒度上的不同。HashTable 的加锁方法是给个方法都加上 synchronized 关键字,这样锁住的是整个 Table 对象。而ConcurrentHashMap 是更细粒度的加锁。
在 JDK 1.7 版本中,ConcurrentHashMap 是采用的分段锁,也就是 Segment 锁,每个 Segment 包含整个 Table 的一部分,这样不同分段之间的并发操作互不影响。
在 JDK 1.8 版本中,ConcurrentHashMap 采用的是 synchronized 和 CAS 对数组上的 Node 加锁,实现对某个链表进行加锁,进一步减少了并发冲突的概率。
它们是加了写锁的ArrayList和ArraySet,锁住的是整个对象,但读操作可以并发执行。
底层采用的 ReentrantLock 进行加锁实现并发控制的
除此之外还有ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque等,至于为什么没有ConcurrentArrayList,原因是无法设计一个通用的而且可以规避ArrayList的并发瓶颈的线程安全的集合类,只能锁住整个list,这用Collections里的包装类就能办到。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。