浅拷贝因仅复制引用类型字段的地址,导致新旧对象共享嵌套数据,多线程下易引发数据竞争;深拷贝则递归创建全新实例,彻底隔离内存,避免竞态。

浅拷贝的副作用在多线程环境中会直接暴露为数据竞争——多个线程操作同一块内存,却误以为各自拥有独立副本。
为什么浅拷贝会共享引用
浅拷贝只复制对象顶层字段:基本类型值被复制,而引用类型(如列表、字典、自定义对象)仅复制地址。这意味着新旧对象的某个字段可能指向同一个底层数据结构。
- 例如 Python 中
shallow_copy = original_list[:],若original_list包含嵌套列表[1, [2, 3]],则切片后两个列表的索引1处仍指向同一个子列表对象 - Java 中实现
Cloneable并调用super.clone(),对Address address字段也只复制引用,而非新建Address实例
竞态条件如何发生
当多个线程同时读写这个被共享的嵌套对象时,执行顺序不可控,结果无法预测。
- 线程 A 执行
shallow_copy[1].append(4) - 线程 B 同时执行
shallow_copy[1].pop() - 原始列表的子列表内容可能被破坏:丢失元素、抛出异常、甚至出现中间状态(如长度突变)
- 没有同步机制时,JVM 或 Python 解释器不保证这些操作的原子性或可见性
深拷贝如何切断风险链
深拷贝递归遍历所有层级,为每个引用类型创建全新实例,彻底消除共享。
- Python 使用
copy.deepcopy(),会对嵌套的 list、dict、自定义类等逐层分配新内存并复制内容 - Java 可通过序列化/反序列化、手动重写
clone()、或使用BeanUtils.copyProperties()配合深拷贝逻辑实现 - Go 中结构体含指针或 map 时,默认赋值仍是浅拷贝;需显式为指针目标分配新内存、逐个复制切片元素
不是所有场景都需要深拷贝
是否采用深拷贝取决于数据可变性与访问模式:
- 若共享对象是只读的(如配置字典、常量列表),浅拷贝安全且高效
- 若线程间仅读取、无写入,也不触发竞态
- 但只要存在“一个线程修改 + 其他线程读取或也修改”的组合,就必须确保数据隔离——深拷贝是最直接的隔离手段










