文档章节

CopyOnWriteArrayList源码剖析

筱虾米
 筱虾米
发布于 06/14 21:06
字数 956
阅读 9
收藏 3

1.1前言

        CopyOnWriteArrayList是JAVA中的并发容器类,同时也是符合写时复制思想的CopyOnWrite容器。写时复制思想即是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

1.2源码分析

1.2.1实现接口

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    CopyOnWriteArrayList实现了List和RandomAccess接口,使得该容器可以具有列表的基本功能和随机访问的特性,并且实现了Cloneable接口和Serializable接口,表示可被克隆和序列化。

1.2.2成员变量

//重入锁
final transient ReentrantLock lock = new ReentrantLock();

//对象数组,用于存放数据,用volatile修饰
private transient volatile Object[] array;

1.2.3构造函数

//设置数组
final void setArray(Object[] a) {
    array = a;
}

//调用setArray,创建一个空的列表
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}

//创建一个包含collection的列表
public CopyOnWriteArrayList(Collection<? extends E> c) {
    Object[] elements;
    //判断集合C的类型是否是CopyOnWriteArrayList,如果是则获取集合的数组,否则进入else
    if (c.getClass() == CopyOnWriteArrayList.class)
        elements = ((CopyOnWriteArrayList<?>)c).getArray();
    else {
        elements = c.toArray();//将集合转为数组
        //判断elements的类型是否为Object[]类型,如果不是则转为Object[]类型
        if (elements.getClass() != Object[].class)
            elements = Arrays.copyOf(elements, elements.length, Object[].class);
    }
    setArray(elements);//设置数组
}
//将toCopyIn转为Object[]类型,然后设置数组
public CopyOnWriteArrayList(E[] toCopyIn) {
    setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}

1.2.4get方法

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

public E get(int index) {
    return get(getArray(), index);
}
final Object[] getArray() {
    return array;
}

        get方法没有加锁也没有cas操作,因此代码非常简单。

1.2.5add方法

//将指定元素添加到列表尾部
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;//添加元素e
        setArray(newElements);//设置数组
        return true;
    } finally {
        lock.unlock();//释放锁
    }
}

1.2.6set方法

//替换列表指定位置的元素
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();//释放锁
    }
}

1.2.7remove方法

//删除指定位置的元素
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));//移动个数为0则表示移除的是数组的最后一个元素,复制elements数组,复制长度为length-1,然后设置数组
        else {//移动个数不为0
            Object[] newElements = new Object[len - 1];//创建一个新数组
            System.arraycopy(elements, 0, newElements, 0, index);//复制index之前的元素
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);//复制index之后的元素
            setArray(newElements);//设置数组
        }
        return oldValue;
    } finally {
        lock.unlock();
    }
}

1.3缺点

  • 内存占用问题,有可能造成频繁的垃圾回收。
  • 数据一致性问题,CopyOnWriteArrayList只能保证数据的最终一致性,不能保证数据的实时一致性。

1.4总结

        对于CopyOnWriteArrayList容器来说,只适合读多写少的并发场景下使用。

© 著作权归作者所有

共有 人打赏支持
筱虾米
粉丝 18
博文 29
码字总数 37089
作品 0
杭州
Java多线程系列之线程安全集合CopyOnWriteArrayList

一、CopyOnWriteArrayList介绍 CopyOnWriteArrayList在Java中通常作为ArrayList的线程安全实现,他继承自List并实现了RandomAccess、Cloneable、java.io.Serializable在支持所有List操作的基...

老韭菜
07/31
0
0
Java并发编程之CopyOnWriteArrayList源码分析

并发包中并发List只有CopyOnWriteArrayList这一个,CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行修改操作和元素迭代操作都是在底层创建一个拷贝数组(快照)上进行的,也就是写时...

狂小白
06/09
0
0
浅谈CopyOnWriteArraySet

CopyOnWriteArraySet结构图 CopyOnWriteArraySet.png CopyOnWriteArraySet主要方法 public boolean add(E e); public boolean remove(Object o); CopyOnWriteArraySet解读主要方法 来看一下p......

小鱼嘻嘻
2017/10/23
0
0
LinkedList&CopyOnWriteArrayList源码分析

前言 由于LinkedList和CopyOnWriteArrayList的源码相对来说比较简单,就放在一起分析了。 LinkedList 就从下面一个例子开始分析 首先看默认构造函数: 再看add()方法 这里需要注意下Node,这就...

MrLeeWen
2017/12/15
0
0
并发编程6:CopyOnWriteArrayList 的写时复制

首先提个问题: 线程安全的 List 集合有什么? CopyOnWriteArrayList 的特点以及使用场景? 如果这个问题你答不上来,那这篇文章可能就对你有些价值。 读完本文你将了解: CopyOnWriteArray...

u011240877
2017/08/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java基础知识,小栗子

来操作一下数组.....注意带参数的变长数组的使用. package com.avatus;import java.util.Random;import java.util.Scanner;public class Main { public static void main(St...

Oh_really
12分钟前
0
0
SSO单点登录PHP简单版

  前面做了一个新项目,需要用户资源可以需要共享。由于之前没有做过这样的东西,回家之后,立马网站百度“单点登录”。帖子很多,甄别之后,这里列几篇认为比较有营养。   http://blog...

slagga
49分钟前
2
0
Java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。 本文参考java 泛型详解、Java中的泛型方法、 java泛型详解 1 概述 泛型在j...

hensemlee
53分钟前
2
0
Annotation注解详细介绍

目录介绍 1.Annotation库的简单介绍 2.@Nullable和@NonNull 3.资源类型注释 4.类型定义注释 5.线程注释 6.RGB颜色纸注释 7.值范围注释 8.权限注释 9.重写函数注释 10.返回值注释 11.@Keep注释...

潇湘剑雨
55分钟前
2
0
一步步编写自己的PHP爬取代理IP项目(二)

这一章节我们正式开展我们的爬虫项目,首先我们先要知道哪个网站能获取到免费代理IP,目前比较火的有西刺代理,快代理等,这里我们拿西刺代理作为例子。 这里就是一个个免费的IP地址以及各自...

NateHuang
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部