system.arraycopy 本身线程安全,因其不操作共享状态;线程安全取决于源数组和目标数组的访问是否受控:只读源与独占目标则安全,否则需同步。

System.arraycopy 是线程安全的,但它的线程安全性取决于你如何使用它,而不是方法本身是否加锁。
System.arraycopy 本身不涉及共享状态
该方法是 native 实现,作用是将源数组中指定范围的元素逐字节(或逐引用)复制到目标数组。它不读写任何全局变量、不修改静态字段、也不依赖外部状态。只要传入的源数组和目标数组对象是确定的,方法执行过程就是纯数据搬运,不会引发内部竞态。
线程安全的关键在数组对象的访问控制
真正决定是否线程安全的,是参与复制的数组(src、dest)是否被多个线程并发读写:
- 如果 src 数组只读(例如初始化后不再修改),且 dest 数组由当前线程独占(未被其他线程访问),则复制过程完全安全;
- 如果 src 正在被其他线程修改(如另一个线程调用 src[i] = x),可能复制出“中间状态”——这不是 arraycopy 的问题,而是未同步的数据竞争;
- 如果 dest 是共享数组,且多个线程同时向其不同索引位置写入(比如线程 A 复制到 [0,9],线程 B 复制到 [10,19]),只要区间不重叠、且 JVM 保证单个数组元素赋值的原子性(对引用类型和 ≤64 位基本类型成立),一般也不会出错;
- 但如果多个线程往 dest 的同一段区域复制,或一边复制一边有其他线程遍历/修改该区域,则必须自行加锁或使用线程安全容器。
常见误用场景
以下情况看似用了 arraycopy,实则存在线程安全风险:
- 用 arraycopy 扩容一个被多线程共享的 ArrayList 内部数组,而扩容期间其他线程仍在读写原数组;
- 多个线程并发调用 Arrays.copyOf,底层都调用 arraycopy,但目标数组引用被意外共享;
- 将 arraycopy 用在 volatile 数组上,误以为 volatile 能保证复制过程的可见性或原子性——其实 volatile 只影响数组引用本身,不影响数组内元素的读写同步。
需要同步的典型做法
当无法确保数组访问互斥时,应在外层控制同步:
- 对共享数组的读写操作统一加 synchronized(如 synchronized(arr) 或 synchronized(lockObj));
- 使用 ReentrantLock 显式控制临界区;
- 改用线程安全的集合类(如 CopyOnWriteArrayList),其 add 等操作内部已封装了安全的复制逻辑;
- 若只是临时拷贝供本线程使用,优先在栈上分配新数组并复制,避免共享。
System.arraycopy 不是“万能安全”的银弹,它像一把锋利的刀——用对了高效可靠,用错了割伤自己。关键不在方法,而在你握刀的手是否稳、目标是否清晰、周围有没有干扰。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











