一、概述
CopyOnWriteArrayList是Java中的并发集合类。 它是一个线程安全的List,可以被多个线程同时访问,但它的实现方法与其他线程安全的集合类不同。 它采用Copy-On-Write(写入时Copy)技术来保证线程安全。
2、CopyOnWriteArrayList原理
Copy-On-Write的原理是,当线程想要改变CopyOnWriteArrayList中的某个元素时,并不直接改变原来的链表,而是将原来的字段复制一次,然后在复制的新链表上执行。 进行更改,以便其他线程仍然可以安全地读取原始字段。 更改完成后,它将用新字段替换原始字段。 这样做的好处是更改操作不会影响其他线程的读操作,因为读操作总是读取原始字段。
三、CopyOnWriteArrayList源码
在CopyOnWriteArrayList的源码中,内部使用了一个volatile修饰的链表来存储数据。 该字段的类型为Object[]typescript 数组 清空,该字段是CopyOnWriteArrayList中元素实际存储的地方。 进行写操作时,会先复制原来的字段,然后对新的链表进行操作,最后用新的字段替换原来的字段。 其实这样做会有一定的成本,而且可以保证线程安全,同时也可以减少锁的使用。
CopyOnWriteArrayList提供了一些基本操作,如add、remove、get、set等,需要注意的是,由于CopyOnWriteArrayList的实现方法,它的迭代器不是强一致的,即在迭代过程中,如果其他线程发生变化CopyOnWriteArrayList 中的元素,迭代器可能会错过这些更改,因为它仍在迭代原始字段。 如果需要强一致的迭代器,可以使用Collections.synchronizedList方法将CopyOnWriteArrayList包装成线程安全的List,这样就可以获得强一致的迭代器。
总的来说,CopyOnWriteArrayList是一个线程安全的List,它采用Copy-On-Write技术来保证线程安全。 即使这样做有一定的开销,也可以减少锁的使用,提高并发性能。 需要注意的是,由于CopyOnWriteArrayList的实现方法的原因,它的迭代器并不是强一致的。 如果需要强一致的迭代器,可以使用 Collections.synchronizedList 方法将 CopyOnWriteArrayList 包装成线程安全的 List。
下面我们详细看一下CopyOnWriteArrayList的源码实现。
1.类的成员变量
CopyOnWriteArrayList类的主要成员变量包括:
java复制代码 /**
* The lock protecting all mutators
*/
final transient ReentrantLock lock = new ReentrantLock();
/**
* The array, accessed only via getArray/setArray.
*/
private transient volatile Object[] array;
其中lock是一个ReentrantLock对象typescript 数组 清空,用于保证多个线程对List进行更改时的同步; array是CopyOnWriteArrayList内部维护的一个字段,用于存储List中的元素。
2、施工方法
CopyOnWriteArrayList类提供了两种构造方法:
scss复制代码 /**
* Creates a new, empty list.
*/
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
/**
* Creates a new list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection of initially held elements
* @throws NullPointerException if the specified collection is null
*/
public CopyOnWriteArrayList(Collection 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);
}
setArray(elements);
}
第一种构造方法用于创建一个空List,其内部维护的字段是一个空链表; 第二种构造方法用于创建一个包含指定集合中元素的List,其中集合中的元素是通过toArray获取的,并将其复制到内部维护的字段中。
3、对外提供方式
CopyOnWriteArrayList类提供了一系列方法,包括:
typescript复制代码 public int size() {...}
public boolean isEmpty() {...}
public boolean contains(Object o) {...}
public Object[] toArray() {...}
public T[] toArray(T[] a) {...}
public boolean add(E e) {...}
public boolean remove(Object o) {...}
public boolean containsAll(Collection c) {...}
public boolean addAll(Collection c) {...}
public boolean addAll(int index, Collection c) {...}
public boolean removeAll(Collection....
4. 核心技能
CopyOnWriteArrayList的核心技能包括:
五、CopyOnWriteArrayList异同
通过上面的分析我们可以发现,CopyOnWriteArrayList的核心思想是通过改变时复制底层链表来实现线程安全。 这些实现方法各有优缺点,下面我们将分别介绍。
优势:
高效的读操作:由于读操作不需要加锁,因此可以避免读写冲突带来的等待时间,从而提高读操作的效率。 线程安全:线程安全是通过在改变时复制底层链表来实现的,从而避免改变操作时的读写冲突。
缺点:
显存占用:由于每次改变都需要复制底层链表,因此会占用较多的显存。 写操作效率低:由于每次写操作都需要复制底层链表,所以写操作效率低。
综上所述,CopyOnWriteArrayList在读多写少的场景下性能较好,但在写多读少的场景下性能较差。 为此,在使用CopyOnWriteArrayList时需要根据实际情况进行选择。
六、CopyOnWriteArrayList使用场景
最后,我们还需要注意CopyOnWriteArrayList的一些使用限制和注意事项:
仅适合大型列表:由于每次更改都需要复制底层链表,因此 CopyOnWriteArrayList 仅适合大型列表。 对于小列表,使用 CopyOnWriteArrayList 可能会导致内存使用率较低。 适用于读多写少的场景:由于每次写操作都需要复制底层链表,因此CopyOnWriteArrayList适合读多写少的场景。 不支持并发更改:CopyOnWriteArrayList不支持并发更改,因为每次更改都需要复制底层链表。 如果需要支持并发更改,请使用其他线程安全的 List 实现。 迭代器快照:由于每个写入操作还会复制底层链表,因此迭代器返回快照而不是列表的实时视图。 如果列表在迭代期间发生更改,则可能会引发 ConcurrentModificationException。
事实上,CopyOnWriteArrayList是一个非常有用的线程安全List实现,它通过在底层链表发生变化时进行复制来实现线程安全。 使用CopyOnWriteArrayList时,需要注意其使用限制和注意事项,从而充分发挥其优点,防止其缺点。