You need to enable JavaScript to run this app. 代码段同步/锁的合理使用:单例类Employee的方法是否需加锁或用原子变量
优惠活动
大模型
产品
解决方案
定价
更多

代码段同步/锁的合理使用:单例类Employee的方法是否需加锁或用原子变量

问题解答

1. Employee单例类的线程安全处理方案

结论:两个方法都需要做线程安全防护,使用synchronized修饰或者将salary改为原子类型两种方案都可行。
原因如下:

  • 单例类的实例是多线程共享的,salary属于共享可变变量,如果不做防护会出现两类问题:
    • updateSalary操作本质是「读当前salary值→计算增量后的值→写回新值」的复合操作,不具备原子性,多线程并发调用时会出现更新丢失的问题。
    • 普通int类型的salary如果没有同步机制,getSalary可能出现可见性问题,线程读到的是CPU缓存里的过期值,不是主内存中的最新值。
  • 两种可行实现方案:
    • 方案1:给两个方法加synchronized修饰:锁对象为单例实例本身,保证同一时间只有一个线程执行这两个方法,同时满足原子性和可见性要求,实现简单,适合并发量不高的场景。
    • 方案2:将salary定义为AtomicInteger类型:get()方法天然保证可见性,addAndGet(increment)底层通过CAS实现原子更新,不需要额外加锁,高并发场景下性能比synchronized更优。

2. 为什么不将synchronized设为方法默认标准

这个思路不成立,核心原因有三点:

  • 不是所有多线程环境下的方法都需要同步:只有方法涉及访问共享可变变量时才需要做线程安全防护。如果方法是无状态的(仅使用方法内部局部变量、线程私有变量或者不可变变量),本身就不存在线程安全问题,加synchronized完全是多余操作。
  • synchronized有不可忽视的性能开销:就算无锁竞争的场景下,JDK对synchronized做了偏向锁、轻量级锁的优化,依然有额外的性能损耗。如果所有方法默认加锁,绝大多数不需要同步的方法会平白损失性能,对高并发应用来说这个开销是完全无法接受的。
  • 同步策略需要结合业务灵活选择:线程安全的实现方案不止synchronized一种,很多场景下用代码块级别的细粒度锁、读写锁、原子类、并发容器等方案更合适。默认给方法加synchronized等于强制使用最粗粒度、最重的锁方案,灵活性极差,完全不符合生产环境的性能优化要求。

举个实际场景的例子:Web服务的业务方法大多只有极少逻辑会涉及共享变量,大部分逻辑都是处理请求参数、调用下游服务、组装返回值。如果所有方法默认加synchronized,服务的并发能力直接降到串行水平,根本没办法支撑生产环境的流量要求。


内容的提问来源于stack exchange,提问作者Agam Goyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 01:48:03