CopyOnWriteArrayList 和 CopyOnWriteArraySet
获得iterator以后,队列被改变,不会抛出ConcurrentModificationException,而是原封不动把没有改动的队列元素输出。@SuppressWarnings("unchecked")
public static void main(String args[]) {
String[] ss = { "aa", "bb", "cc" };
List list1 = new CopyOnWriteArrayList(Arrays.asList(ss));
List list2 = new ArrayList(Arrays.asList(ss));
Iterator itor1 = list1.iterator();
Iterator itor2 = list2.iterator();
list1.add("New");
list2.add("New");
try {
printAll(itor1);
} catch (ConcurrentModificationException e) {
System.err.println("Shouldn't get here");
}
try {
printAll(itor2);
} catch (ConcurrentModificationException e) {
System.err
.println("Will get here.ConcurrentModificationException occurs!");
}
}
@SuppressWarnings("unchecked")
private static void printAll(Iterator itor) {
while (itor.hasNext()) {
System.out.println(itor.next());
}
}
-----------OUTPUT-----------
aa
bb
cc
Will get here.ConcurrentModificationException occurs!
ConcurrentMap
java.util.concurrent.ConcurrentMap 接口和 ConcurrentHashMap 实
现类只能在键不存在
时将元素加入到 map 中,只有在键存在并映射到特定值时才能从 map 中删除一个元素。主要定义了下面几个方法(K 表示键的类型,V 表示值的类型):
- V putIfAbsent(K key,V value):如果指定键已经不再与某个值相关联,则将它与给定值关联。
- boolean remove(Object key,Object value):只有目前将键的条目映射到给定值时,才移除该键的条目。
- boolean replace(K key,V oldValue,V newValue):只有目前将键的条目映射到给定值时,才替换该键的条目。
- V replace(K key,V value):只有目前将键的条目映射到某一值时,才替换该键的条目。
- putIfAbsent() 方法用于在 map 中进行添加。这个方法以要添加到 ConcurrentMap 中的键的值为参数,就像普通的 put() 方法,但是只有在 map 不包含这个键时,才能将键加入到 map 中。如果 map 已经包含这个键,那么这个键的现有值就会保留。 putIfAbsent() 方法是原子的。等价于下面的代码(除了原子地执行此操作之外):
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
6. 像 putIfAbsent() 方法一样,重载后的 remove() 方法有两个参数:键和值。在调用时,
只有当键映 射到指定的值时才从 map 中删除这个键。如果不匹配,那么就不删除这个键,
并返回 false。如果值 匹配键的当前映射内容,那么就删除这个键,这个方法是原子性的。
这种操作的等价源代码(除了原子地执行此操作之外):
if (map.containsKey(key) && map.get(key).equals(value)) {
map.remove(key);
return true;
} else return false;
总之,ConcurrentMap 中定义的方法是原子性的。
BlockingQueue
- boolean add(Object e):将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。
- public boolean offer(Object element):将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插素,而只是抛出一个异常。
- public Object remove():获取并移除此队列的头。
- public Object poll();获取并移除此队列的头,如果此队列为空,则返回 null。
- public Object element();获取但是不移除此队列的头。此队列为空时将抛出一个异常。
- public Object peek();获取但不移除此队列的头;如果此队列为空,则返回 null。
ArrayBlockingQueue :一个由数组支持的有界队列。
LinkedBlockingQueue :一个由链接节点支持的可选有界队列。
PriorityBlockingQueue :一个由优先级堆支持的无界优先
DelayQueue :一个由优先级堆支持的、基于时间的调度队列。
SynchronousQueue :一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。
前两个类 ArrayBlockingQueue 和 LinkedBlockingQueue 几乎相同,只是在后备存储器
方 面 有 所 不 同 , LinkedBlockingQueue 并 不 总 是 有 容 量 界 限 。 无 大 小 界 限 的
Link
edBlockingQueue 类 在 添 加 元 素 时 永 远 不 会 有 阻 塞 队 列 的 等 待 ( 至 少 在 其 中 有
Integer.MAX_VALUE 元素之前不会)。
PriorityBlockingQueue 是具有无界限容量的队列,它利用所包含元素的 Comparable 排
序顺序来以逻辑顺序维护元素。可以将它看作 TreeSet 的可能替代物。例如,在队列中加入字符
符串 One、Two、Three 和 Four 会导致 Four 被第一个取出来。对于没有天然顺序的
元素,可以为构造函数提供一个 Comparator 。不过对 PriorityBlockingQueue 有一个技巧。
从 iterator() 返回的 Iterator 实例不需要以优先级顺序返回元素。如果必须以优先级顺序遍
历所 有 元 素 , 那 么 让 它 们 都 通 过 toArray() 方 法 并 自 己 对 它 们 排 序 , 像
Arrays.sort(pq.toArray()) 。
DelayQueue 实现可能是其中最有意思(也是最复杂)的一个。加入到队列中的元素必须实现新的 Delayed 接口(只有一个方法 long getDelay(java.util.concurrent.TimeUnit
unit))。因为队列的大小没有界限,使得添加可以立即返回,但是在延迟时间过去之前,不
能从队列中取出元素。如果多个元素完成了延迟,那么最早失效/失效时间最长的元素将第
一个取出。