JAVA Concurrent包 中的并发集合类
我们平时写程序需要经常用到集合类,比如ArrayList、HashMap等,但是这些集合不能够实现并发运行机制,这样在服务器上运行时就会非常的消耗资源和浪费时间,并且对这些集合进行迭代的过程中不能进行操作,否则会出现错误,例如下面程序:
[Java]
public class CollectionModifyExceptionTest {
public static void main(String[] args) {
Collection users = new ArrayList();
users.add(new User("张三",28));
users.add(new User("李四",25));
users.add(new User("王五",31));
Iterator itrUsers = users.iterator();
while(itrUsers.hasNext()){
System.out.println("正在执行!");
User user = (User)itrUsers.next();
if("李四".equals(user.getName())){
users.remove(user);
} else {
System.out.println(user);
}
}
}
}
程序在执行过程中会报错, 因为定义了一个ArrayList类型的集合,但是在对集合进行迭代的时候又出现了users.remove(user),即从集合从删除数据,对于普通的集合来说这是不允许的,Java 5以后出现的并发集合类就是专门针对普通集合出现不能并发和不能在迭代过程中修改数据等问题而出现的。
并发集合类主要有:
ConcurrentHashMap; ConcurrentSkipListMap;
ConCurrentSkipListSet; CopyOnWriteArrayList;
CopyOnWriteArraySet; ConcurrentLinkedQueue;
下面其中的某些集合类进行分别简述:
ConcurrentHashMap支持完全并发的检索和更新所希望的可调整并发的哈希表。此类遵守与 Hashtable
相同的功能规范,并且包括对应于 Hashtable 的每个方法的方法版本。不过,尽管所有操作都是线程安全的,但检索操作不 必锁定,并且不
支持以某种防止所有访问的方式锁定整个表。此类可以通过程序完全与 Hashtable 进行互操作,这取决于其线程安全,而与其同步细节无关。
主要构造方法有:
[java]
ConcurrentHashMap(); //创建一个带有默认初始容量、加载因子和 concurrencyLevel 的新的空映射。
ConcurrentHashMap(int initialCapacity); //创建一个带有指定初始容量、默认加载因子和 concurrencyLevel 的新的空映射。
ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel); //创建一个带有指定初始容量、加载因子和并发级别的新的空映射。
ConcurrentHashMap(Map<> t); //构造一个与给定映射具有相同映射关系的新映射。
ConcurrentLinkedQueue是一个基于链接节点的、无界的、线程安全的队列。此队列按照
FIFO(先进先出)原则对元素进行排序,队列的头部 是队列中时间最长的元素。队列的尾部
是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。当许多线程共享访问一个公共 collection
时,ConcurrentLinkedQueue 是一个恰当的选择,此队列不允许 null 元素。
主要构造方法有:
[java]
ConcurrentLinkedQueue(); //创建一个最初为空的 ConcurrentLinkedQueue。
ConcurrentLinkedQueue(Collection<> c);// 创建一个最初包含给定 collection 的元素的 ConcurrentLinkedQueue,按照此 collection 迭代器的遍历顺序来添加元素
CopyOnWriteArrayList是ArrayList
的一个线程安全的变形,其中所有可变操作(添加、设置,等等)都是通过对基础数组进行一次新的复制来实现的。这一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法更
有效。在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时,它也很有用。“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内绝不会更改,因此不可能发生冲突,并且迭代器保证不会抛出
ConcurrentModificationException。自创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。不支持迭代器上更改元素的操作(移除、设置和添加)。这些方法将抛出
UnsupportedOperationException。
主要构造方法有:
[java]
CopyOnWriteArrayList(); // 创建一个空列表。
CopyOnWriteArrayList(Collection<> c); //按照 Collection 的迭代器返回元素的顺序,创建一个包含指定 Collection 的元素的列表。
CopyOnWriteArrayList(E[] toCopyIn); //创建一个新的 CopyOnWriteArrayList,它保持给定数组的副本。
CopyOnWriteArraySet是对其所有操作使用 CopyOnWriteArrayList 的 Set。因此,它共享以下相同的基本属性:
它最适合于 set 大小通常保持很小、只读操作远多于可变操作以及需要在遍历期间防止线程间冲突的应用程序。
它是线程安全的。
因为通常需要复制整个基础数组,所以可变操作(添加、设置、移除,等等)的开销巨大。
迭代器不支持可变移除操作。
使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
主要构造方法包括:
[java]
CopyOnWriteArraySet(); //创建一个空 set
CopyOnWriteArraySet(Collection<> c); //创建一个包含指定 Collection 中所有元素的 set
讲完并发集合类以后再回到本文刚开始的例子中,如果将Collection users = new
ArrayList();改写成Collection users = new
CopyOnWriteArrayList();再运行程序,程序就会正常进行了,结果如下:
[java]
正在执行!
{name:'张三',age:28}
正在执行!
正在执行!
{name:'王五',age:31}