流程控制是防止高并发多维报表动态拼装数据缩水的核心手段,通过四阶段不可逆流程(快照获取→有效行统计→目标数组构建→数据注入)、关键节点校验、最小粒度同步及状态机驱动实现风险前置拦截。

流程控制是防止高并发多维报表动态拼装时数据缩水的核心手段。它不靠单点技术“兜底”,而是通过明确阶段划分、严格执行顺序和关键节点校验,把“漏数据”“错行数”“空洞填充”等风险堵在流程入口和中间环节。
分阶段拆解拼装流程,禁止跨阶段读写共享数据
将整个拼装过程划为四个不可逆阶段:快照获取 → 有效行统计 → 目标数组构建 → 数据注入。每个阶段只操作前一阶段输出,不回读原始 reportData:
- 快照获取阶段仅执行 volatile 读取,得到 int[][] snapshot,此后所有逻辑基于该快照,不访问 reportData 变量本身
- 有效行统计阶段遍历 snapshot,逐行判空,记录 actualRows;跳过任何 length 不匹配或 null 的行,不计入搬运范围
- 目标数组构建阶段根据 actualRows + addRows 创建新二维数组,不复用原数组长度,避免把 null 行带入
- 数据注入阶段先用 System.arraycopy 搬运 actualRows 行,再从索引 actualRows 开始逐行填入新增数据,不依赖原数组“空位”
关键节点强制校验,失败即中断不降级搬运
在流程中嵌入轻量但确定的校验点,一旦不满足条件立即终止当前拼装任务,防止带病数据进入下游:
- 快照获取后检查 snapshot != null,防止空引用导致后续 NPE 或静默跳过
- 每行注入前校验该行是否为非 null 且长度等于预期列数(如 expectedColCount),否则抛出 IllegalArgumentException 或标记丢弃,不填入目标数组
- arraycopy 执行前确认源起始索引 ≥ 0、拷贝长度 ≤ 源数组长度、目标起始索引 ≥ 0、目标数组长度 ≥ 目标起始索引 + 拷贝长度,避免越界静默截断
同步边界收窄到最小粒度,避免流程阻塞放大
流程控制必须与并发控制解耦:锁只用于两个原子动作——读取 volatile 引用和更新 reportData 引用;其余所有流程步骤(统计、扩容、拷贝、填充)全部在锁外执行:
- 主线程获取快照后立即释放锁,其他线程可同时获取同一快照进行各自拼装
- arraycopy 耗时操作完全异步,不阻塞任何读操作;即使某次拼装耗时较长,也不影响其他线程使用旧快照生成报表
- 最终 reportData = newData 这一行更新仍需 synchronized 或 CAS,但因只改引用、不改内容,持有锁时间极短
引入状态机驱动流程,拒绝非法状态跃迁
为拼装任务实例维护简单状态(INIT → SNAPSHOT_OK → ROWS_COUNTED → ARRAY_BUILT → DONE),每次状态变更前验证前置条件是否满足:
- 只有 SNAPSHOT_OK 状态才允许进入 ROWS_COUNTED,否则报错“未获取快照不可统计”
- 只有 ROWS_COUNTED 才能创建目标数组;若尝试跳过统计直接 build,流程引擎拒绝执行
- DONE 状态后禁止任何修改,防止重复注入或覆盖











