java并发编程之 CopyOnWriteArrayList
来源:互联网 发布:网络关注平台出租 编辑:程序博客网 时间:2024/06/14 03:53
我们都知道在java容器中ArrayList是线程不安全的,而vector是线程安全的。那么针对线程安全和不安全来说,这两个容器应该是够用了,为什么还要出现一个CopyOnWriteArrayList这个容器呢?CopyOnWriteArrayList是线程安全的,那么它较vector有哪些优势呢?
看一下vector的add和get源码
/** * Appends the specified element to the end of this Vector. * * @param e element to be appended to this Vector * @return {@code true} (as specified by {@link Collection#add}) * @since 1.2 */ public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }/** * Returns the element at the specified position in this Vector. * * @param index index of the element to return * @return object at the specified index * @throws ArrayIndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size()}) * @since 1.2 */ public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); }
可以看到对于vector的add和get方法都被synchronize修饰了,这就说明了当我在获取数据的时候,其他线程也是不能获取的,所有的读和写都会被阻塞。
再来看CopyOnWriteArrayList中的源码
/** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (index > len || index < 0) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+len); Object[] newElements; int numMoved = len - index; if (numMoved == 0) newElements = Arrays.copyOf(elements, len + 1); else { newElements = new Object[len + 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index, newElements, index + 1, numMoved); } newElements[index] = element; setArray(newElements); } finally { lock.unlock(); } }
简单的概括就是,在添加数据的时候,系统会复制一个新的list然后添加的时候往新的array添加,当然这个新的list是lock确保线程安全的。
等新的list操作完成之后,再把旧的list引用的地址指向它即可。但是旧的list是没有加锁的,所以读的操作是不会阻塞的。
copyOnWriterArrayList通过消耗空间的方式来提高系统的并发性,但是这样浪费了空间,容易造成minor Gc ,严重的话会造成full gc。所以要根据情况来选择使用。
阅读全文