0
点赞
收藏
分享

微信扫一扫

CopyOnWriteArrayList源码分析

IT影子 2022-09-19 阅读 19

目录

概述

基本方法以及源码分析

无参构造方法

有参构造方法

set(int index,E element)

add(E e)添加元素至尾部

add(int index, E element)在指定下标添加元素

remove(int index)删除指定下标的元素

removeRange(int fromIndex, int toIndex)删除指定范围的元素

clear()清空集合

addAll(int index, Collection c)在指定位置批量添加元素


概述

CopyOnWriteArrayList是一种线程安全的集合,通过ReentrantLock来实现集合的安全性。当我们对集合进行写入操作时,并不会直接在集合中写入,而是先将当前的集合复制,复制出一个新的集合,在新的集合中进行写入操作,写入 完成后,将原集合的引用指向新的集合。

CopyOnWriteArrayList的设计思想是读写分离,在保证写入操作的安全性时,也不会影响并发读取操作。它的内部使用Object[]数组,允许多线程并发读取,但只有一个线程可以进行写入操作。

基本方法以及源码分析

无参构造方法

//默认的构造方法,数组初始化
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }

有参构造方法

//    有参构造方法
    public CopyOnWriteArrayList(Collection<? extends E> c) {
        Object[] elements;
//        copy的集合与当前集合是同一个Class对象
        if (c.getClass() == CopyOnWriteArrayList.class)
//        	将当前集合强转为CopyOnWriteArrayList并转为数组,存入elements中
            elements = ((CopyOnWriteArrayList<?>)c).getArray();
        else {
//        	直接将当前集合c赋给elements
            elements = c.toArray();
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
//            数组类型不是Object[]类型,对数组进行复制操作
            if (elements.getClass() != Object[].class)
                elements = Arrays.copyOf(elements, elements.length, Object[].class);
        }
        setArray(elements);
    }

set(int index,E element)

//    修改指定下标的值
    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();
        }
    }

add(E e)添加元素至尾部

//    添加元素至集合尾部
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
//        加锁
        lock.lock();
        try {
//        	得到原数组
            Object[] elements = getArray();
            int len = elements.length;
//            添加操作复制原数组内容的同时长度+1
            Object[] newElements = Arrays.copyOf(elements, len + 1);
//            元素添加至数组尾部
            newElements[len] = e;
//          保存新数组(旧数组=>新数组)
            setArray(newElements);
            return true;
        } finally {
//        	释放锁
            lock.unlock();
        }
    }

add(int index, E element)在指定下标添加元素

//    在指定下标添加元素
    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)
//            	复制原数组,长度加+1
                newElements = Arrays.copyOf(elements, len + 1);
            else {
//            	创建一个新数组,新数组长度=原数组长度+1
                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();
        }
    }

remove(int index)删除指定下标的元素

//    删除指定下标的元素
    public E remove(int index) {
        final ReentrantLock lock = this.lock;
//        加锁
        lock.lock();
        try {
//        	得到当前数组
            Object[] elements = getArray();
            int len = elements.length;
//            获取要删除的元素和下标
            E oldValue = get(elements, index);
//            获取被删除元素的位置
            int numMoved = len - index - 1;
//            如果=0说明删除的是最后一个元素
            if (numMoved == 0)
//            	复制原数组长度-1
                setArray(Arrays.copyOf(elements, len - 1));
            else {
//            	创建数组,长度为原数组-1
                Object[] newElements = new Object[len - 1];
//                该操作与add(int index, E element)方法同理
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            return oldValue;
        } finally {
//        	解锁
            lock.unlock();
        }
    }

removeRange(int fromIndex, int toIndex)删除指定范围的元素

	// 删除指定范围的元素
	void removeRange(int fromIndex, int toIndex) {
		final ReentrantLock lock = this.lock;
		lock.lock();
		try {
			Object[] elements = getArray();
			int len = elements.length;

//          判断下标位置是否合理,不合理抛异常
			if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
				throw new IndexOutOfBoundsException();

			// 计算新数组长度
			int newlen = len - (toIndex - fromIndex);
			// 获取结束下标的位置
			int numMoved = len - toIndex;
			// =0 ,复制原数组从0到newlen位置
			if (numMoved == 0)
				
				setArray(Arrays.copyOf(elements, newlen));
			else {
				// 新建一个数组,长度为newlen的
				Object[] newElements = new Object[newlen];
//              该操作与add(int index, E element)方法同理
				System.arraycopy(elements, 0, newElements, 0, fromIndex);
				System.arraycopy(elements, toIndex, newElements, fromIndex, numMoved);
				setArray(newElements);
			}
		} finally {
			lock.unlock();
		}
	}

clear()清空集合

	// 清空集合中元素
	public void clear() {
		final ReentrantLock lock = this.lock;
		// 加锁
		lock.lock();
		try {
			// 数组初始化
			setArray(new Object[0]);
		} finally {
			lock.unlock();
		}
	}

addAll(int index, Collection<? extends E> c)在指定位置批量添加元素

 // 在指定位置批量添加元素
    public boolean addAll(int index, Collection<? extends E> c) {
      // 将集合c转换为数组并赋值给cs
        Object[] cs = c.toArray();
        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);
//        如果集合c为空,则直接返回false
            if (cs.length == 0)
                return false;
            int numMoved = len - index;
            Object[] newElements;
//         如果numMoved等于0,则代表在原集合末尾添加
            if (numMoved == 0)
//         复制原集合,个数为原集合元素个数加要添加的元素个数
                newElements = Arrays.copyOf(elements, len + cs.length);
            else {
//         创建新集合
                newElements = new Object[len + cs.length];
//              该操作与add(int index, E element)方法同理
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index,
                                 newElements, index + cs.length,
                                 numMoved);
            }
//               复制数组至新数组
            System.arraycopy(cs, 0, newElements, index, cs.length);
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
举报

相关推荐

0 条评论