Java多线程与并发库高级应用-同步集合
ArrayBlockingQueue
LinkedBlockingQueue
数组是连续的一片内存
链表是不连续的一片内存
传统方式下用Collections工具类提供的synchronizedCollection方法来获得同步集合。
java5中提供了如下一些同步集合类:
> 通过看java.util.concurrent包下的介绍可以知道有哪些并发集合
> ConcurrentHashMap 可以进行并发操作的HashMap,并发的HashMap还有 Collections.synchronizedMap(m) ,有了ConcurrentHashMap后,Collections.synchronizedMap(m)不怎么使用了。
>ConcurrentSkipListMap 实现了SortedMap<K,V> ,类似于TreeMap
>ConcurrentSkipListSet 实现了SortedSet, 类似于TreeSet
> CopyOnWriteArrayList
> CopyOnWriteArraySet
传统方式下的Collection在迭代时,不允许对集合进行修改。
使用Iterator对集合进行迭代时不能修改集合
public class CollectionModifyExceptionTest { public static void main(String[] args) { List<String> strs = new ArrayList<>(); strs.add("aaa"); strs.add("bbb"); strs.add("ccc"); Iterator iterator = strs.iterator(); while(iterator.hasNext()){ System.out.println("....."); String value = (String)iterator.next(); if("aaa".equals(value)){ strs.remove(value); }else{ System.out.println(value); } } } }
以上代码在遍历集合时,对集合进行修改,会抛出异常
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at com.java.thread.CollectionModifyExceptionTest.main(CollectionModifyExceptionTest.java:17)
异常抛在这一句
String value = (String)iterator.next();
/** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { // return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException();//此处抛异常 } }
然而在将"aaa" 改成"bbb"时,却没有抛出异常
因为在遍历到 bbb 时,cursor为1(0,1,2),将 bbb 移除后size为2 进行下次遍历是cursor为 2
所以hasNext()返回的为false 就不会进入循环。
要解决这个问题,可以使用 CopyOnWriteArrayList 在写的时候有一份拷贝,
public static void main(String[] args) { List<String> strs = new CopyOnWriteArrayList(); strs.add("aaa"); strs.add("bbb"); strs.add("ccc"); Iterator iterator = strs.iterator(); while(iterator.hasNext()){ System.out.println("....."); String value = (String)iterator.next(); if("aaa".equals(value)){ strs.remove(value); }else{ System.out.println(value); } } }