文章目录
一、List
1、CopyOnWriteArrayList
CopyOnWriteArrayList是Java并发包java.util.concurrent中提供的一种线程安全的ArrayList。它的主要特性在于写时复制(Copy-On-Write)的并发策略,即在修改操作(如添加、修改、删除元素)时,不是直接修改原数组,而是先复制一份底层数组,然后在副本上进行修改操作,修改完成后再将原数组的引用指向新的数组。这种机制保证了修改操作的线程安全性,同时读取操作可以完全不用加锁,从而实现了读操作的高性能。
CopyOnWriteArrayList适用于读多写少的场景,比如缓存。当应用程序的读操作频率远高于写操作时,CopyOnWriteArrayList是一个很好的选择。因为每次修改操作都会创建一个底层数组的副本,从而避免了读取操作受到写入操作的干扰。同时,由于每个线程都在自己的副本上进行操作,因此不存在读取过程中数据被其他线程修改的问题,从而保证了数据的一致性。
然而,CopyOnWriteArrayList也存在一些缺点。由于写操作时需要拷贝数组,如果原数组的内容较多,可能会消耗较大的内存,并可能导致年轻代(Young Generation)或老年代(Old Generation)的垃圾回收(GC)。此外,如果数据量非常大,每次添加或修改元素都需要重新复制数组,性能开销可能会比较大。因此,在选择使用CopyOnWriteArrayList时,需要根据具体的应用场景和需求进行权衡。
总的来说,CopyOnWriteArrayList是一种适用于读多写少场景的线程安全ArrayList实现,通过写时复制的机制保证了数据的一致性和读取性能,但在写操作频繁或数据量较大的情况下可能存在性能问题。
CopyOnWriteArrayList 是一个线程安全的动态数组,非常适合用于读多写少的并发场景。下面是一个简单的示例,演示了 CopyOnWriteArrayList 的基本用法:
package chatpter07;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestCopyOnWriteArrayList {
public static void main(String[] args) {
// 创建一个CopyOnWriteArrayList实例
List<String> list = new CopyOnWriteArrayList<>();
// 在多线程环境下添加元素
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
list.add("Element from thread 1: " + i);
System.out.println("Thread 1 added element: " + list.get(list.size() - 1));
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
list.add("Element from thread 2: " + i);
System.out.println("Thread 2 added element: " + list.get(list.size() - 1));
}
});
// 启动线程
thread1.start();
thread2.start();
// 等待线程执行完毕
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 读取并打印列表中的元素
System.out.println("Final list content:");
for (String element : list) {
System.out.println(element);
}
}
}
执行结果:
Thread 1 added element: Element from thread 1: 0
Thread 1 added element: Element from thread 1: 1
Thread 1 added element: Element from thread 1: 2
Thread 1 added element: Element from thread 1: 3
Thread 1 added element: Element from thread 1: 4
Thread 2 added element: Element from thread 2: 0
Thread 2 added element: Element from thread 2: 1
Thread 2 added element: Element from thread 2: 2
Thread 2 added element: Element from thread 2: 3
Thread 2 added element: Element from thread 2: 4
Final list content:
Element from thread 1: 0
Element from thread 2: 0
Element from thread 1: 1
Element from thread 1: 2
Element from thread 1: 3
Element from thread 1: 4
Element from thread 2: 1
Element from thread 2: 2
Element from thread 2: 3
Element from thread 2: 4
Process finished with exit code 0
二、Set
1、CopyOnWriteArraySet
继承于AbstractSet类,对应的基础容器为HashSet。其内部组合了一个CopyOnWriteArrayList对象,它核心操作是基于CopyOnWriteArrayList实现
2、concurrentSkipListSet
是线程安全的有序集合,对应的基础容器为TreeSet。它继承了AbstractSet,并实现NavigableSet接口。CurrentSkipListSet是通过CurrentSkipListMap实现的
三、Map
1、ConcurrentHashMap
对应的基础容器是HashMap,JDK7中采用一种更加细粒度的“分段锁”加锁机制,JDK8中采用CAS无锁算法
(1) JDK7
采用segment分段锁的方式实现,一个CurrentHashMap中包含一个segment数组,一个segment中包含一个HashEntry数组,HashEntry数组中每个元素是一个链表结构。当对hashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。当一个线程占用锁访问其中一段数据时,其他段的数据也能被其他线程访问,实现并发访问。

- Segment源码

- Segment是CurrentHashMap的一个内部主要的组成,继承自ReentrantLock。volatile修饰HashEntry<K,V>[] table,可以保证在数组扩容时的可见性。
- volatile修饰HashEntry的数据value和下一个节点next,保证了多线程环境下数据获取时的可见性。
(2)JDK8
在JDK1.8中,ConcurrentHashMap已经抛弃了Segment分段锁机制,存储结构采用Node数组 + 链表+红黑树的组合方式,利用CAS + Synchronized来保证并发更新的安全。


- 在锁的实现上,抛弃了原有的Segment分段锁,采用CAS + synchronized实现更加细粒度的锁。将锁的级别控制在了更细粒度的哈希桶数组元素级别,只需要锁住这个链表的头结点(或红黑树的根节点),就不会影响其他的哈希桶数组元素的读写,大大提高了并发度。
特性:
- 不支持key或者value为null
- 因为ConcurrentHashMap工作于多线程环境,如果ConcurrentHashMap.get(key) 返回为null,就无法判断值为null还是key不存在(即:存在二义性)。而单线程HashMap可以用containsKey(key)判断是否包含这个key。
- 与HashMap迭代器是强一致性不同,ConcurrentHashMap迭代器是弱一致性
- ConcurrentHashMap的迭代器创建后,就会按照哈希表结构遍历每个元素,但在遍历过程中,内部元素可能会发生变化,如果变化发生在已遍历过的部分,迭代器就不会反映出来,如果变化发生在未遍历部分,迭代器就会发现并反映出来,这就是弱一致性。
- 这样迭代器线程可以使用原来老的数据,而写线程也可以并发的完成改变,保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。
API介绍:
- get方法
- 因为Node和HashEntry的元素value和指针next是用volatile修饰的,在多线环境下线程A修改节点的value或者新增节点的时候是对线程B可见的。
2、ConcurrentSkipListMap
对应的基础容器为TreeMap,其内部的SkipList(跳表)结构是一种可以代替平衡树的数据结构,默认是按照Key升序的
本文详细介绍了Java并发包中的CopyOnWriteArrayList,CopyOnWriteArraySet以及ConcurrentHashMap的原理、适用场景和性能特点,特别是CopyOnWriteArrayList的写时复制策略及其在读多写少场景的优势和局限。还涵盖了ConcurrentHashMap在JDK7和JDK8版本中的锁机制优化。
673

被折叠的 条评论
为什么被折叠?



