CopyOnWriteArrayList源码分析

一、CopyOnWriteArrayList

CopyOnWriteArrayList是一个线程安全的Arraylist,它的内部存储结构采用数组,  线程安全是基于

Reentrantlock实现的,  当对CopyOnWriteArrayList进行写入操作事,  并不影响进行并发的读取操作,

实现读写分离操作的思想。下面就是CopyOnWriteArrayList部分关于写入操作的源码:

set( )方法:修改指定下标的元素

 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()方法:添加元素到末尾:

  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();
        }
    }

add()方法:按指定下标添加:

 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)
                newElements = Arrays.copyOf(elements, len + 1);
            else {
            	// 新数组长度加一
                newElements = new Object[len + 1];
                // 从下标0开始复制原数组到新数组
                System.arraycopy(elements, 0, newElements, 0, index);

                // 从传入下标的位置开始,从原数组复制到新数组对应位置加1
                System.arraycopy(elements, index, newElements, index + 1,
                                 numMoved);
            }
            
            // 将新的元素加入到对应下标位置 
            newElements[index] = element;
            
            // 将数组重新指向
            setArray(newElements);
        } finally {
        	// 解锁
            lock.unlock();
        }
    }

remove()方法:将指定下标的元素删除:

  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;
            if (numMoved == 0)
            	// 如果是最后一个就将,数组重新复制一个份,但不复制最后一个
                setArray(Arrays.copyOf(elements, len - 1));
            else {
            	// 否则,创建一个新数组,数组长度为,原长度减一
                Object[] newElements = new Object[len - 1];
                // 将原数组重新复制一份到新数组
                System.arraycopy(elements, 0, newElements, 0, index);
                
                // 从旧数组中的对应下标的+1开始,复制到新数组中的对应位置
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            // 将旧数据返回
            return oldValue;
        } finally {
        	// 解锁
            lock.unlock();
        }
    }

clear()方法:讲数组内的元素清除:

 public void clear() {
    	// 加锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        	// 讲数组设置为空数组
            setArray(new Object[0]);
        } finally {
        	// 解锁
            lock.unlock();
        }
    }

小结:

CopyOnWriteArrayList由于只在写入时加锁,所以只能保证数据的最终一致性,不能保证数据的实

时一致性。同时由于add()set()remove()等修改操作需要复制整个数组,所以会有内存开销

大的问题,   由于每次写入操作时,进行了Copy复制原数组,所以无需扩容;

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CopyOnWriteArrayListJava 中的一个线程安全的集合类,它的实现原理是在写操作时创建一个新的数组来存储数据,从而实现了读写分离,保证了读操作的线程安全性。 具体的实现原理如下: 1. CopyOnWriteArrayList 内部使用一个数组来存储数据。 2. 在进行写操作(添加、修改、删除)时,先创建一个新的数组,将原数组的数据复制到新数组中,并在新数组上进行写操作。 3. 写操作完成后,将新数组赋值给原数组,从而实现了数据的更新。 4. 在进行读操作时,直接读取原数组的数据,保证了读操作的线程安全性。 CopyOnWriteArrayList 的实现原理保证了读操作的线程安全性,因为读操作不会对原数组进行修改,而是读取原数组的数据。但是写操作会创建一个新的数组,因此写操作的性能相对较低。 范例:<<引用[1]:CopyOnWriteArrayList原理。 文章目录 一、 CopyOnWriteArrayList介绍二、 CopyOnWriteArrayList原理三、 CopyOnWriteArrayList 属性介绍四、 构造器以及添加add方法五、 get(int index)六、 remove(int index)七、 遍历 。 引用:CopyOnWriteArrayList实现原理及源码分析。1 List list = Collections.synchronizedList(new ArrayList()); 。 CopyOnWriteArrayList 实现原理如下: 1. 内部使用一个数组来存储数据。 2. 在进行写操作时,先创建一个新的数组,将原数组的数据复制到新数组中,并在新数组上进行写操作。 3. 写操作完成后,将新数组赋值给原数组,从而实现了数据的更新。 4. 在进行读操作时,直接读取原数组的数据,保证了读操作的线程安全性。 5. 写操作会创建一个新的数组,因此写操作的性能相对较低。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值