Java二维数组本身不提供原子性保障,访问任意元素均非天然线程安全;其本质是“一维数组的数组”,gridi涉及两次引用跳转和一次内存读取,整体非原子,需依赖同步机制保障线程安全。
Java 中二维数组本身不提供原子性保障,访问它的任意元素都不是天然线程安全的。是否线程安全,取决于你如何读写——关键不在“二维”结构,而在于“共享”与“并发修改”。如果多个线程只读不写,或写操作被正确同步,就能安全;否则极易出现脏读、丢失更新或越界异常。
Java 的二维数组(如 int[][] grid = new int[10][10];)本质是“一维数组的数组”:外层数组存储的是指向内层数组对象的引用。这意味着:
grid[i] 是原子的(引用读取本身不可分割),但 grid[i][j] 涉及两次引用跳转 + 一次内存读取,整体非原子grid[i] = new int[10]; 是原子的(替换引用),但 grid[i][j] = value; 包含加载、计算、存储三步,可能被中断以下代码在多线程下极易出错:
grid[x][y]++,结果只加 1 次而非 2 次grid[0][0],线程 B 可能长期看不到该更新(无同步或 volatile)grid[i] = null;,另一个线程同时访问 grid[i][j] → NullPointerException
grid[i] 尚未 new 出内层数组,直接访问会抛异常不必全盘锁住整个二维数组——按需选择粒度合适的方案:
立即学习“Java免费学习笔记(深入)”;
synchronized(grid[i]) 锁定某一行(前提是该行对象不被外部替换);或为每个 grid[i] 初始化为 new Object() 作为独立锁对象AtomicIntegerArray 替代内层数组,如 AtomicIntegerArray[] rows = new AtomicIntegerArray[n];
ConcurrentHashMap<Pair<Integer,Integer>, Integer> 替代密集数组几个容易被忽略但影响安全性的点:
volatile 没用——它只保证引用可见性,不保证内层数组内容可见final int[][] grid 仅防止引用被重赋值,内部元素仍可被修改Arrays.setAll() 或 Stream 初始化时,确保初始化完成后再发布引用(可用 final 字段 + 构造器保证安全发布)ReentrantLock 实现可重入的细粒度控制