并发中数组状态保护的关键是切断外部引用并确保拷贝时机一致:构造器和getter需用Arrays.copyOf或clone做保护性拷贝;引用类型数组还需深拷贝元素;多线程优先用独立副本或CopyOnWriteArrayList;必须同步时应覆盖完整逻辑链;更推荐volatile引用替换实现无锁线程安全。

在并发环境中用数组拷贝保护状态,核心不是“怎么拷”,而是“谁在什么时候、以什么方式持有数组”。关键在于切断外部对内部可变状态的直接引用,并确保拷贝动作发生在一致的时间点。
构造和返回时必须做保护性拷贝
当你类的构造器接收数组参数,或 getter 方法要返回内部数组时,绝不能直接赋值或返回引用:
- 构造器中:用
Arrays.copyOf(src, src.length)或src.clone()创建新副本,再赋给成员变量 - getter 中:返回
Arrays.copyOf(internalArray, internalArray.length),而不是internalArray - 对引用类型数组(如
Date[]),若元素本身可变,还需对每个元素做深拷贝(例如 new Date(date.getTime())),否则外部仍可通过元素引用破坏内部约束
多线程间传递数据优先用独立副本
避免让多个线程共享同一数组实例。安全做法是让每个线程操作自己的拷贝:
- 读多写少场景:用
CopyOnWriteArrayList,它的 add/remove 自动完成底层数组复制,读操作无锁且看到的是快照 - 临时计算或导出:在方法栈内
new String[n]或int[n]作为 dest,调用System.arraycopy填充后即用即弃 - 配置或模板类:初始化后将数组声明为
private final,并确保后续不修改——此时它天然就是只读快照,拷贝也始终一致
必须同步时,保护整个逻辑链而非单行代码
如果无法避免共享数组(如复用缓冲区),System.arraycopy 必须放在同步块里,且同步范围要覆盖所有依赖状态的操作:
- 用私有
final Object lock = new Object();作锁对象,不锁数组本身(防外部误锁) - 同步块内包含:检查源状态 → 调用
arraycopy→ 更新 volatile 标志或替换引用 - 例如:
synchronized(lock) { System.arraycopy(src, 0, dest, 0, src.length); isReady = true; }
比加锁更推荐不可变+引用替换
放弃“原地更新”思维,转向每次变更都生成新数组并原子替换引用:
- 写操作:创建新数组 → 用
arraycopy填充 → 通过volatile字段(如private volatile int[][] data)发布 - 读操作:直接使用该字段,无需同步,天然线程安全
- 优势是无锁、无阻塞、无断层风险,适合配置推送、报表生成等场景

















