• Vector和CopyOnWriteArrayList源码解析


    前面介绍的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中,只有增删改操作添加了锁,查询则没有,使多线程能并行访问。

  • 相关阅读:
    Effective C# 原则50:了解ECMA标准(译)
    Effective C# 原则47:选择安全的代码(译)
    DevExpress小结(简略)
    Effective C#49:为C#2.0做好准备(译)
    Effective C# 原则45:选择强异常来保护程序(译)
    我在犹豫是不是该收集这几首MP3
    用C#预览视频文件(简略)
    DevExpress库的学习总结(简略)
    SharePoint 2010 隐藏快速启动栏(左侧导航)
    将 Excel 导入到 SharePoint 列表
  • 原文地址:https://www.cnblogs.com/linlf03/p/12633792.html
Copyright © 2020-2023  润新知