推荐使用 AtomicInteger 实现线程安全的自增序列号,声明为 private static final AtomicInteger counter = new AtomicInteger(1),构造时调用 getAndIncrement() 或 incrementAndGet();若用普通 static int 则需 synchronized 同步,避免非原子操作导致重复 ID。

Java 中用静态变量实现对象自增序列号,核心是利用 static 变量在类加载时初始化、被所有实例共享 的特性,但必须注意多线程安全和初始化顺序问题。直接 ++ 操作在并发下会出错,需加同步或使用原子类。
用 AtomicInteger 保证线程安全
推荐首选 AtomicInteger,它内部基于 CAS 实现无锁自增,性能好且天然线程安全:
- 声明为
private static final AtomicInteger counter = new AtomicInteger(1); - 构造方法中调用
this.id = counter.getAndIncrement();(从 1 开始,先取后增)或counter.incrementAndGet()(先增后取) - 避免在静态块中重置或外部修改,防止破坏序列连续性
用 synchronized 确保传统方式安全
若需兼容老版本或逻辑较复杂(比如带格式化、跳号等),可用同步块包裹自增逻辑:
- 定义
private static int nextId = 1; - 在构造器中写:
synchronized (MyClass.class) { this.id = nextId++; } - 锁对象建议用
MyClass.class而非this(此时 this 还未创建),确保类级别互斥
注意静态变量初始化时机与单例干扰
静态变量在类首次主动使用时初始化,但若类中有多个静态字段或静态代码块,顺序可能影响初始值:
立即学习“Java免费学习笔记(深入)”;
- 不要在静态块里依赖其他尚未初始化的静态变量
- 如果类被 Spring 管理为单例,且构造频繁,仍需按上述方式保证每个新实例获得唯一 ID(不是单例共用一个 ID)
- 避免将序列号生成逻辑放在 static 方法中并被外部反复调用,否则可能绕过构造流程导致 ID 重复或跳变
不推荐直接用普通 static int ++
看似简洁,但在多线程环境下极大概率产生重复 ID:
-
nextId++是“读-改-写”三步操作,非原子 - 两个线程同时读到 5,各自加 1 后都写回 6,结果丢失一次递增
- 即使只在单线程启动阶段创建对象,也建议养成用原子类的习惯,避免后续扩展时埋坑


















