美文网首页
锁性能提升——CopyOnWriteArrayList

锁性能提升——CopyOnWriteArrayList

作者: 柚子过来 | 来源:发表于2018-06-21 14:22 被阅读0次

在说CopyOnWriteArrayList之前先说下ArrayList为什么不是线程安全的,通常意义上的线程安全是指在多个线程同时执行的 情况下不会出现数据不一致或者脏数据等,也就是多个线程一起执行与一个线程执行多次的结果应该是一样的。所以其实如果一个操作如果不是原子操作,又没有做线程安全的处理(如锁),那就会有线程安全问题。
比如我们看ArrayList的add方法:

public boolean add(E e) {
    modCount++;
    add(e, elementData, size);
    return true;
}
private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;       (1)
    size = s + 1;                   (2)
}

从代码可以看出是先添加数据,再更新size,所以如果线程1执行到了(1),但是还没执行(2),这时线程2又add,那就会出现数据丢失。

与ArrayList对应的线程安全类有Vector,但是Vector是对add、get、remove等方法添加了synchronized同步保证的线程安全,所以性能较低。

在实际的应用场景中读操作可能远远多于写操作,所以去除get操作的同步开销可以提升性能,但是这时就要考虑到如果去除了get操作的同步,但是由于集合的fail-fast机制,如果去除了get操作的同步,如果一个线程在get,另一个线程add的话就会抛出ConcurrentModificationException异常。

CopyOnWriteArrayList使用了CopyOnWrite的思想,在add或者remove数据的时候,先复制一份数组的副本,对副本进行add操作,然后再将实际数组的引用指向副本,完成更新:

  public boolean add(E e) {
    synchronized (lock) {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    }
}

 final void setArray(Object[] a) {
    array = a;
}

 public E remove(int index) {
    synchronized (lock) {
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = elementAt(elements, index);
        int numMoved = len - index - 1;
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        else {
            Object[] newElements = new Object[len - 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            setArray(newElements);
        }
        return oldValue;
    }
}

可以发现CopyOnWrite操作的复制行为保证了在进行写操作时,可以并发的进行读操作并且不会有并发问题。而写操作本身是加锁的,所以写操作也不会有并发问题

但是CopyOnWriteArrayList这样实现就有弱一致性的缺点,它只能保证最终一致性,因为线程读取到的可能不是最新的数据。

相关文章

  • 锁性能提升——CopyOnWriteArrayList

    在说CopyOnWriteArrayList之前先说下ArrayList为什么不是线程安全的,通常意义上的线程安全...

  • 锁性能提升——ReadWriteLock

    这篇文章主要记录下ReadWriteLock的实现原理与用处,ReentrantLock可以实现线程安全,但是它的...

  • 锁的性能提升

    对于锁的性能提升的考虑,主要包括以下几点 减小锁持有时间 减小锁粒度 读写分离锁来替换独占锁 锁分离 锁粗化 1....

  • Java并发之CopyOnWriteArrayList

    CopyOnWriteArrayList是线程安全的、并且读操作无锁的ArrayList。不像ArrayList默...

  • JDK的锁优化

    JDK1.6重点提升了并发性能,HotSpot开发团队实现了各种锁优化技术,如适应性自旋锁、锁消除、锁粗化、轻量级...

  • ios中常用的锁

    ios中常用的锁 为什么要用到锁?锁是什么 在平时的开发过程中,为了提升我们应用程序的运行效率,性能,我们会经常使...

  • 锁分析(上)

    锁性能分析 iPhone 12真机测试,锁的性能数据对比图 性能从高到低排序:OSSpinLock(自旋锁)>os...

  • CopyOnWriteArrayList同步写思想的理解

    CopyOnWriteArrayList 简介public class CopyOnWriteArrayList<...

  • ReadWriteLock读写锁

    读写锁,分场景优化,提升性能。 读写锁遵守的基本原则: 允许多个线程同时读共享变量。 只允许一个线程写共享变量。 ...

  • CopyOnWriteArrayList简介

    CopyOnWriteArrayList,写数组的拷贝,支持高效率并发且是线程安全的,读操作无锁的ArrayLis...

网友评论

      本文标题:锁性能提升——CopyOnWriteArrayList

      本文链接:https://www.haomeiwen.com/subject/pzvqyftx.html