java静态变量天然不线程安全,需通过类锁(synchronized静态方法或myclass.class块)、原子类、volatile(仅限简单状态标志)或消除共享(threadlocal/实例变量)来保障线程安全。

Java 中静态变量天然不线程安全,因为它被所有线程共享,而 JVM 不保证读写操作的原子性、可见性和有序性。要保证多线程下对静态变量的安全访问,核心不是“锁变量本身”,而是统一协调所有线程的访问入口——用类锁(Class 对象)来控制临界区。
用 synchronized 修饰静态方法
这是最直接的方式:JVM 自动以当前类的 MyClass.class 作为锁对象,所有线程调用该方法前必须获取这把唯一的锁。
- 适合逻辑简单、更新集中,比如计数器递增、单例初始化
- 写法简洁:
public static synchronized void increment() { count++; } - 注意:不能靠
this或实例对象实现同步,因为静态方法没有this
用 synchronized(MyClass.class) 显式加锁
比静态方法更灵活,只锁定真正需要保护的代码段,避免无关逻辑被阻塞。
- 可在一个块里安全读写多个静态变量,保证原子性
- 明确体现“锁什么、护什么”,例如:
synchronized (Counter.class) { count++; log.info("updated"); } - 务必使用
MyClass.class,不要用 new Object() 或 this,否则锁对象不唯一,起不到同步效果
优先考虑原子类替代基础类型
对整数、布尔、引用等常见类型,AtomicInteger、AtomicBoolean 等是更轻量、无锁的方案。
- 声明:
private static AtomicInteger count = new AtomicInteger(0); - 更新:
count.incrementAndGet(),底层基于 CAS,天然支持原子性和可见性 - 局限:仅适用于单变量原子操作;多个变量需协同更新时,仍需配合锁或事务机制
慎用 volatile,明确适用边界
volatile 能解决可见性和重排序问题,但不能保证复合操作原子性。
- 适合:状态标志(
private static volatile boolean running = true;)、初始化完成标记、只写一次后只读的配置 - 不适合:任何含“读-改-写”的操作,如
count++、list.add() - 可配合 double-checked locking 使用,但不能单独用于计数类逻辑
从设计源头减少共享
很多线程安全问题其实源于不必要的全局状态。
-
ThreadLocal:为每个线程提供独立副本,适合上下文信息(用户 ID、格式化器、事务状态) - 改用实例变量 + 容器管理:将静态变量改为普通成员变量,由 Spring 等框架管理生命周期,通过依赖注入传递
- 关键一问:这个值是否真的必须被所有线程共同读写?多数时候答案是否定的
不复杂但容易忽略:同步只是手段,消除共享才是更根本的解法。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











