static 配合 atomiclong 可在单 jvm 内实现线程安全、无锁、低开销的全局自增 id 生成器,适用于监控指标、日志序列号等场景,但不适用于分布式唯一 id。

用 static 配合 AtomicLong 或 AtomicInteger,能在单 JVM 进程内快速构建线程安全、无锁、低开销的全局自增 ID 生成器。它不依赖数据库或外部服务,适合监控指标、日志序列号、单节点请求流水号等场景。
明确适用范围:仅限单节点 JVM 内有效
static 变量绑定的是类加载器,生命周期与应用进程一致。这意味着:
- ID 在整个 Spring Boot 应用运行期间持续递增,重启后从初始值重新开始
- 集群中多个实例各自维护独立计数,彼此不共享、不冲突
- 不能用于分布式唯一 ID(如订单号),此时应选 Snowflake、Redis INCR 或数据库 sequence
核心实现:用 AtomicLong 替代普通 static long
避免 count++ 这类非原子操作引发的丢数问题。正确写法是:
- 声明为 private static final:保证不可变引用,防止被意外替换
- 使用 AtomicLong.incrementAndGet():底层基于 CAS,无锁且高效
- 初始值可设为 1 或指定起始偏移(如时间戳高位 + 自增)
示例代码:
public class SimpleIdGenerator {<br> private static final AtomicLong id = new AtomicLong(1);<br> public static long nextId() {<br> return id.incrementAndGet();<br> }<br>}
封装成可管理组件:暴露方法 + 支持重置 + 接入监控
裸 static 字段难以测试和运维,必须封装为 Spring Bean:
- 提供
nextId()、current()、resetTo(long)等标准接口 - 在单元测试
@BeforeEach中调用resetTo(1),避免测试间状态污染 - 通过 Micrometer 的
Gauge注册当前值,接入 Prometheus 实时查看趋势 - 可选添加
@ReadOperation暴露/actuator/idgen查看状态
避坑要点:内存、可见性与初始化顺序
看似简单,但容易踩雷:
- 不存业务对象引用:比如把 Request 或 User 存进 static Map,会导致 GC 失效、内存泄漏
- 不依赖未就绪配置:static 初始化早于 @ConfigurationProperties,避免读取空配置导致默认值异常
- 不暴露 public static 可变字段:破坏封装,无法加锁、无法审计修改来源
- 高并发下优先 AtomicLong 而非 synchronized:后者有锁竞争开销,前者 CAS 在多数场景更轻量











