当前位置: 首页 > news >正文

Collections.synchronizedList是如何将List变为线程安全的

一、synchronizedList 的线程安全实现逻辑

  1. 包装类选择
    调用 Collections.synchronizedList(List<T> list) 时,会根据传入 List 是否实现 RandomAccess 接口(如 ArrayList 实现该接口,LinkedList 不实现),返回不同的包装类:
  • 实现 RandomAccess:返回 SynchronizedRandomAccessList(继承自 SynchronizedList);
  • 未实现:返回 SynchronizedList
    public static <T> List<T> synchronizedList(List<T> list) {return (list instanceof RandomAccess ?new SynchronizedRandomAccessList<>(list) :new SynchronizedList<>(list));}
  1. 核心锁机制
    线程安全的核心是 对象锁(mutex)+ synchronized 同步块
  • SynchronizedList 继承自 SynchronizedCollection,在父类中初始化 mutex 锁对象(mutex = this,即包装类实例本身);
  • getsetaddremove 等所有修改/查询方法,均通过 synchronized (mutex) 包裹,确保同一时刻只有一个线程能执行这些方法。
static class SynchronizedCollection<E> implements Collection<E>, Serializable {private static final long serialVersionUID = 3053995032091335093L;final Collection<E> c;  // Backing Collectionfinal Object mutex;     // Object on which to synchronizeSynchronizedCollection(Collection<E> c) {this.c = Objects.requireNonNull(c);mutex = this;}SynchronizedCollection(Collection<E> c, Object mutex) {this.c = Objects.requireNonNull(c);this.mutex = Objects.requireNonNull(mutex);}public int size() {synchronized (mutex) {return c.size();}}public boolean isEmpty() {synchronized (mutex) {return c.isEmpty();}}public boolean contains(Object o) {synchronized (mutex) {return c.contains(o);}}public Object[] toArray() {synchronized (mutex) {return c.toArray();}}public <T> T[] toArray(T[] a) {synchronized (mutex) {return c.toArray(a);}}public Iterator<E> iterator() {return c.iterator(); // Must be manually synched by user!}public boolean add(E e) {synchronized (mutex) {return c.add(e);}}public boolean remove(Object o) {synchronized (mutex) {return c.remove(o);}}public boolean containsAll(Collection<?> coll) {synchronized (mutex) {return c.containsAll(coll);}}public boolean addAll(Collection<? extends E> coll) {synchronized (mutex) {return c.addAll(coll);}}public boolean removeAll(Collection<?> coll) {synchronized (mutex) {return c.removeAll(coll);}}public boolean retainAll(Collection<?> coll) {synchronized (mutex) {return c.retainAll(coll);}}public void clear() {synchronized (mutex) {c.clear();}}public String toString() {synchronized (mutex) {return c.toString();}}// Override default methods in Collection@Overridepublic void forEach(Consumer<? super E> consumer) {synchronized (mutex) {c.forEach(consumer);}}@Overridepublic boolean removeIf(Predicate<? super E> filter) {synchronized (mutex) {return c.removeIf(filter);}}@Overridepublic Spliterator<E> spliterator() {return c.spliterator(); // Must be manually synched by user!}@Overridepublic Stream<E> stream() {return c.stream(); // Must be manually synched by user!}@Overridepublic Stream<E> parallelStream() {return c.parallelStream(); // Must be manually synched by user!}private void writeObject(ObjectOutputStream s) throws IOException {synchronized (mutex) {s.defaultWriteObject();}}}

二、效率低下的原因

SynchronizedList 采用 “粗粒度锁” 实现:
所有方法共用同一把 mutex 锁,无论操作是读(如 get)还是写(如 add),都会独占锁。这意味着即使多个线程仅执行读操作,也需要排队等待锁释放,无法实现“读-读并发”,导致并发效率显著低于 CopyOnWriteArrayList 等细粒度锁/无锁实现。

三、遍历需额外加锁的原因

SynchronizedList 内部的锁仅保证 单个方法调用的原子性,但无法保证 多步操作(如遍历)的原子性

  • iterator() 方法直接返回底层 List 的迭代器(未加锁),迭代器本身不具备线程安全性;
  • 若不加外部锁,可能出现“并发修改异常”(如线程 A 遍历 hasNext() 时存在元素,线程 B 立即删除该元素,线程 A 调用 next() 时会报错)。

因此,官方要求遍历 SynchronizedList 时,需在外部用 synchronized (list) 包裹迭代逻辑,确保遍历全程独占锁,避免并发修改问题。

 public Iterator<E> iterator() {return c.iterator(); // Must be manually synched by user!}

示例代码如下:

List list = Collections.synchronizedList(new ArrayList());
// 正确遍历方式
synchronized (list) {Iterator i = list.iterator(); while (i.hasNext()) {foo(i.next());}
}
http://www.lryc.cn/news/623940.html

相关文章:

  • vs studio 2017项目不支持studio vs2022
  • 【k8s】Kubernetes核心概念与架构详解
  • 从0实现系统设计
  • Leetcode 15 java
  • GitHub Copilot:AI编程助手的架构演进与真实世界影响
  • 浜掕仈缃戝ぇ鍘侸ava姹傝亴鑰呴潰璇曠幇鍦猴細褰撲弗鑲冮潰璇曞畼閬囦笂鎼炵瑧绋嬪簭鍛樿阿椋炴満
  • Conda 环境 在AI 私有化部署 有怎么用?
  • 电力设备状态监测与健康管理:基于多源异构数据融合的技术实现
  • 五、redis入门 之 客户端连接redis
  • 计算机网络 HTTP1.1、HTTP2、HTTP3 的核心对比及性能分析
  • ReactNode 类型
  • Java项目中短信的发送
  • 密码学系列 - 零知识证明(ZKP) - 多种承诺方案
  • Java ConcurrentHashMap 深度解析
  • 【LeetCode 热题 100】(八)二叉树
  • EC11编码器
  • 集成电路学习:什么是SIFT尺度不变特征变换
  • 43 C++ STL模板库12-容器4-容器适配器-堆栈(stack)
  • 基于DSP+ARM+FPGA架构的储能协调控制器解决方案,支持全国产化
  • 电子电气架构 --- 自动驾驶汽车的下一步发展是什么?
  • 下降路径最小和
  • 【网络通信】TCP/IP 协议全方位解析​
  • java如何把字符串数字转换成数字类型
  • OpenCV 图像处理核心技术:边界填充、算术运算与滤波处理实战
  • android aidl相关学习
  • 常用的SQL语句
  • java16学习笔记
  • topographic terrain
  • AMBA-AXI and ACE协议详解(七)
  • 计算机网络---跳板机与堡垒机