1.Vector和Hashtable是早期jdk的一部分,Collections.synchronizedXxx等工厂方法创建。
2.同步容器类的问题
容器上常见的复合操作包括:迭代、跳转以及条件运算,虽然这些容器是线程安全的,但是当线程并发地去修改,会出现意外的情况。
for(int i = 0 ; i < vector.size(); i++){}
在多线程中,vector的size可能发生变化,直接抛出ArrayIndexOutOfBoundsException异常,解决方案,牺牲伸缩性、并发性
synchronized(vector){
for(int i = 0 ; i < vector.size(); i++){}
}
迭代器与ConCurrentModificationException
当迭代过程中被修改,会抛出ConCurrentModificationException,上述讲到给容器加锁,当容器内的元素处理时间过长,严重影响性能,如果不希望在迭代期间对容器枷锁,可以“克隆”容器,并在副本中迭代,由于副本被封闭在线程中,这样就避免了
ConCurrentModificationException,这样就牺牲内存
3.并发容器类
ConcurrentHashMap代替基于散列的Map、CopyOnWriteArrayList代替ArrayList,Queue和BlockingQueue、PriorityQueue相对应ConcurrentLinkedQueue,并发容器解决ConCurrentModificationException问题
ConcurrentHashMap也是基于散列的MapHashTable,性能差主要是由于所有操作需要竞争同一把锁,而如果容器中有多把锁,每一把锁锁一段数据,这样在多线程访问时不同段的数据时,就不会存在锁竞争了,这样便可以有效地提高并发效率。这就是ConcurrentHashMap所采用的"分段锁"思想,ConcurrentHashMap的主干是个Segment数组,Segment继承了ReentrantLock,所以它就是一种可重入锁(ReentrantLock)。在ConcurrentHashMap,一个Segment就是一个子哈希表,Segment里维护了一个HashEntry数组,并发环境下,对于不同Segment的数据进行操作是不用考虑锁竞争的。(就按默认的ConcurrentLeve为16来讲,理论上就允许16个线程并发执行),HashEntry是目前我们提到的最小的逻辑处理单元了。一个ConcurrentHashMap维护一个Segment数组,一个Segment维护一个HashEntry数组。
CopyOnWriteArrayList:“写入时复制”,就是上述讲的克隆容器