线程安全CopyOnWriteArrayList

ArrayList 线程不安全问题

ArrayList 底层的数据结构其实是数组结构。

public boolean add(E e) {
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  elementData[size++] = e;
  return true;
}

我们来看一下 ArrayList 的 add 方法源码,上面的代码主要做了两步操作,判断当前 size+1 是否超过了数组长度和将当前数据放到数组的当前 size+1 的下标中。

这里就体现出线程不安全的情况了,在 ensureCapacityInternal(size + 1); 这步操作时,如果是多线程的情况下,如果数组大小为10,此时的 size 为9,那么线程 A 首先判断 size+1 不会导致数组下标越界,然后挂起。随后线程 B 也走到这一步发现不需要扩容,这时候执行完赋值方法后,size 大小为10了。此时线程A开始赋值,就会导致数组下标越界异常。

另外一种情况就是在 elementData[size++] = e; 这步操作的时候。我们为了好理解可以把这行代码拆分为如下代码:

elementData[size] = e;
size++;

我们发现这行代码其实并不是一个原子性的操作。它是首先将值新增到当前size位置,然后进行 size++。这个时候就会出现值被覆盖的问题。首先线程 A 将值新增到当前 size 后,在还未进行 size++ 的时候,线程 B 也将值新增到了当前的 size,此时就会造成线程A新增的值被覆盖。

LinkedList 线程不安全问题

LinkedList 的底层数据结构为双向链表,每个节点存储着数据值以及前继指针和后继指针的指向地址值。

public boolean add(E e) {
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  elementData[size++] = e;
  return true;
}

This chapter requires login to view full content. You are viewing a preview.

Login to View Full Content

Course Curriculum

3

框架与 I/O:Spring、Netty 与 Web 容器

理解 Spring Boot 自动装配、AOP 与事务原理,掌握 Netty Reactor 模型及 Tomcat 连接处理机制,构建高内聚、易扩展的应用服务层。
4

高性能中间件:消息、缓存与存储

熟练运用 MySQL 索引/事务、Redis 缓存策略、Kafka/RocketMQ 消息可靠性,以及 ZooKeeper 分布式协调,搭建稳定、解耦的分布式数据底座。
6

云原生:容器化、可观测性与工程效能

通过 Docker/K8s 实现弹性部署,集成 Metrics/Logs/Traces 构建可观测体系,推动 DevOps 与自动化,让架构在云上持续交付与进化。