0%

并发List

本文介绍并发List,有几点说明:

  • 其在Java容器中的划分位置见[1]
  • 根接口为List,其内元素允许为NULL
  • 并发List的常见使用场景不太用到迭代器,故本文对迭代器不作深入叙述
  • 并发List可被用于“生产者-消费者模型”,当然“生产者-消费者模型”最常使用并发Queue
  • 接下来介绍其常见的3个子类:
    • CopyOnWriteArrayList
    • Vector
    • SynchronizedList

接下来对具体实现子类的介绍,主要基于以下几个维度:

  • 是否有界,分为“设计是否有界”和“实际是否有界”,实际有“设计有界,实际有界”,“设计无界,实际无界”和“设计无界,实际有界,可称为假性无界”这3种情况
  • 底层数据结构基于“数组”,还是“链表”
  • 实现操作的线程安全策略
  • 生成的迭代器性质[1]

一、CopyOnWriteArrayList

1、核心原理

  • 设计无界,实际有界(在扩增数组时,目标大小如果大于等于Integer.MAX_VALUE,会抛出异常)
  • 基于数组
  • 对于修改操作使用ReentrantLock lock锁实现操作的线程安全,即会阻塞加锁,默认是一个“非公平锁”,具体实现修改的策略是“实例变量array指向底层元素对象数组,修改时首先将当下对应的元素对象数组复制到新元素对象数组,然后在新元素对象数组上进行修改操作,最后将array赋值为指向新元素对象数组”;对于读取操作,不加锁,始终基于array指向的当前元素对象数组。综合以上两点,其适用场景如下:
    • 写少读多
    • 集合不大,否则复制操作较为耗时
    • 实时性要求不高,因为读取时可能读取到旧元素对象数组
  • 生成特殊的“快照式”迭代器,其特殊性体现在:一般的“快照式”迭代器在生成迭代器时复制内容,而它在生成迭代器时不进行复制而是直接指向原内容,等到后续CopyOnWriteArrayList实例进行修改操作如上所述指向新内容时,它指向的内容才与CopyOnWriteArrayList实例指向的内容被动完成脱钩

2、构造参数

  • Collection<? extends E> c:初始化元素来源集合
  • E[] toCopyIn:初始化元素来源集合

二、Vector

Vector有子类Stack,Stack中“栈数据结构”的方法(比如push()pop()peek()等)通过调用Vector的方法实现。

1、核心原理

  • 设计无界,实际有界
  • 基于数组
  • 使用synchronized实现读写时的线程安全,故属于同步容器
  • 生成“快速失败”迭代器

2、构造参数

  • Collection<? extends E> c:初始化元素来源集合
  • int initialCapacity:初始容量大小
  • int capacityIncrement:扩容增量大小

三、SynchronizedList

java.util.Collections类中的内部类。

1、核心原理

  • 基于所传入的List实例,有界性也依赖于它
  • 使用synchronized实现操作的线程安全,故属于同步容器
  • 生成所传入List实例的迭代器,故迭代器性质须具体情况具体分析

2、构造参数

  • List<E> list:SynchronizedList实例所基于的底层List实例,注意其跟“初始化元素来源集合”不一样,后者在复制后就不再有关联
  • Object mutex:传入的锁对象

参考文献

[1]《Java容器》
[2]https://juejin.cn/post/6844903576339218440

您的支持将鼓励我继续分享!