system.arraycopy本身不是并发工具,它不提供同步、不保证原子性、也不解决竞态条件;其作用仅是高效复制数组内存内容,需配合锁、volatile或不可变设计等并发控制机制才能安全使用。

System.arraycopy 本身不是并发工具,它不提供同步、不保证原子性、也不解决竞态条件。但它在并发数组处理中扮演关键支撑角色——前提是用对场景、管住上下文。
明确职责边界:它搬数据,不保安全
arraycopy 只做一件事:把 src 数组某段内存内容,按字节或引用粒度,原样复制到 dest 数组指定位置。它不关心谁在读、谁在写、是否多线程。所谓“并发应用”,其实是把它嵌入到安全的并发模式里:
- 它不替代 synchronized 或 Lock,但可放在临界区内高效执行“快照复制”
- 它不防止数据撕裂,但配合不可变设计,能让读操作零阻塞
- 它不管理生命周期,但复用已有数组能显著降低 GC 压力,这对长时运行的并发服务至关重要
典型安全用法:快照复制 + 引用替换
这是最常用也最推荐的并发模式,尤其适合读多写少场景(如配置推送、报表生成、事件处理器列表更新):
- 每次写操作都 new 一个新数组,用 arraycopy 填充数据(例如拼接多个子数组、过滤后复制)
- 用 volatile 字段或 AtomicReference 原子更新对外暴露的数组引用
- 读线程直接访问该引用,全程无锁、无拷贝、无同步开销
示例:动态更新处理器列表
private volatile Handler[] handlers = EMPTY;synchronized (lock) {
Handler[] newHandlers = new Handler[oldLength + 1];
System.arraycopy(oldHandlers, 0, newHandlers, 0, oldLength);
newHandlers[oldLength] = newHandler;
handlers = newHandlers; // 对读线程立即可见
}
谨慎复用共享数组:必须加锁且覆盖全程
若因内存限制必须复用全局缓冲区(如环形日志 buffer、共享解码区),则 arraycopy 必须包裹在同步块中,且同步范围要包含所有相关读写操作:
- 锁对象必须是专用 final Object,避免锁数组实例(易被外部误锁)
- 同步块内应完成:确认源状态稳定 → 执行 arraycopy → 更新就绪标记或引用
- 禁止只锁 arraycopy 调用本身——断层往往来自锁外的并发修改
反例:volatile 修饰数组引用后直接调用 arraycopy —— volatile 不保证数组元素的可见性与原子性。
避开高危误用:这些做法等于没防
以下看似用了 arraycopy,实则无法规避并发问题:
- 多线程同时向同一 dest 数组不同索引写入,未加锁也未隔离区域(即使不重叠,也可能因缓存未同步导致读线程看到撕裂数据)
- 在 ArrayList 扩容过程中并发调用 arraycopy —— 底层数组 elementData 正被多个线程读写
- 用它替代 Arrays.copyOf 实现“深拷贝”——它只复制引用,对象内容仍共享
- 认为 length 小就安全,忽略小数据下 JNI 开销可能超过简单循环,反而拖慢响应
它不是银弹,但足够锋利——用对地方,就是并发数组处理中最稳的一把扳手。











