work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Vector和CopyOnWriteArrayList源码解析

Posted on 2020-04-04 20:37  work hard work smart  阅读(286)  评论(0编辑  收藏  举报

前面介绍的ArrayList和LinkedList, 在多线程的场景中就不适合了。JDK提供了线程安全的List。

Vector和CopyOnWriteArrayList是线程安全的

1、Vector

这个类属性和方法同ArrayList,主要区别是Vector在其主要方法上都加上了synchronized关键字,这样就达到了线程安全的目的。

 

2、CopyOnWriteArrayList源码分析

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    final transient ReentrantLock lock = new ReentrantLock();

    //使用数组存储数据
    private transient volatile Object[] array;
}

 相对于ArrayList,多了一个用于线程安全的lock,少了计数size 

 

3、CopyOnWriteArrayList构造函数

    //1、空构造函数
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }

    //2、集合构造函数
    public CopyOnWriteArrayList(Collection<? extends E> c) {
        Object[] elements;
        if (c.getClass() == CopyOnWriteArrayList.class)
            elements = ((CopyOnWriteArrayList<?>)c).getArray();
        else {
            elements = c.toArray();
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elements.getClass() != Object[].class)
                elements = Arrays.copyOf(elements, elements.length, Object[].class);
        }
	//赋值给当前array
        setArray(elements);
    }

    //3、数字构造函数
    public CopyOnWriteArrayList(E[] toCopyIn) {
        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
    }
    //setArray方法
    final void setArray(Object[] a) {
        array = a;
    }

  主要是将参数解析为一个数字对象,然后复制给array

 

 

4、添加操作

    //1、添加单个元素
    public boolean add(E e) {    
    }
    //2、添加单个元素到某个位置
    public void add(int index, E element) {
       
    }
    //3、添加集合元素
    public boolean addAll(Collection<? extends E> c){
    }

    //4、添加集合从某个位置开始
    public boolean addAll(int index, Collection<? extends E> c) {
    

  主要分析下public boolean add(E e)

    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
 	//1、获取锁对象
        lock.lock();
        try {
	    //2、增加元素
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
	    //3、释放锁
            lock.unlock();
        }
    }

  需要注意的是:CopyOnWriteArrayList并没有ArrayList的自动扩容(1.5倍),添加了一次执行Arrays.copyOf操作,这个会成为性能瓶颈

 

5、删除操作

我们主要看下

    public E remove(int index) {
        final ReentrantLock lock = this.lock;
	//1、获取锁
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(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;
        } finally {
            lock.unlock();
        }
    }

  

6、修改操作

我们看下

    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index);

            if (oldValue != element) {
		//直接获取元素,并替换
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

  

7、查询操作

    private E get(Object[] a, int index) {
        return (E) a[index];
    }

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

  这里的get不是线程安全的。

而Vector的查询操作,synchronized 修饰,是线程安全的。

    public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

  总结: 在Vector中,无论增删操作,还是查询操作,统统都加上synchronized锁,

而在CopyOnWriteArrayList中,只有增删改操作添加了锁,查询则没有,使多线程能并行访问。