乱弹java并发(三)-- CopyOnWriteArrayList和CopyOnWriteArraySet

CopyOnWriteArrayList是基于“写时复制”策略的线程安全的数组,它的特点是写加锁读不加锁,了解过ConcurrentHashMap的原理之后,再理解它的原理就比较简单了,来看看两个关键方法:

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

    public E get(int index) {
        return (E)(getArray()[index]);
    }

    final Object[] getArray() {
        return array;
    }
从代码中可以看到,在往数组中添加元素时,把整个数组拷贝一份把数据插入到新数组中,然后用新数组代替老数组,这样保证多个线程不会再同一个时间点读到不一致的数据,在插入时加了全局锁,所以多个线程不能同时插入数据,而读操作时完全没有锁的,这里面array时一个volatile变量,这点很关键,在插入操作的最后设置这个volatile变量,由volatile在JMM中的happens-before语义,已及hp的传递性,保证了写操作完成之后,写操作更新的数据对读线程时可见的。和ConcurrentHashMap一样,CopyOnWriteArrayList也只能保证弱一致性。由于CopyOnWriteArrayList写操作要拷贝整个数组,所以整个操作对时间的消耗和对GC产生的压力都是比较可观的,而读操作由于无锁,所以读操作比较高效而且读线程之间不会发生阻塞,所以这个结构适用于读操作远远多于写操作的场景。

CopyOnWriteArraySet完全时基于CopyOnWriteArrayList来实现的,这里不再赘述。



你可能感兴趣的:(JAVA,编程技术)