You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java多线程场景下静态volatile变量自增出现重复值如何解决?

问题根本原因

n++ 本质是读-改-写三个非原子操作的组合:

  • 从主内存读取n的当前值
  • 在线程工作内存执行+1计算
  • 将计算后的新值写回主内存
    volatile关键字仅能保证变量的可见性(每次读取直接取主内存最新值、修改后立刻同步回主内存),但无法保证这三步操作的原子性。多线程并发执行时会出现多个线程拿到同一个n的取值,各自自增后写回主内存,最终产生重复编号。

可行解决方案

方案1:使用java.util.concurrent.atomic包下的原子类(推荐,无锁实现性能高)

将static volatile int n=0替换为AtomicInteger类型,调用其原子自增方法实现编号生成,底层通过CAS实现操作原子性,同时满足可见性要求。
修改后的代码示例:

public class Producer implements Runnable{
    private String str;
    private Fifo f;
    private int i;
    // 替换为原子整型,默认初始值为0
    private static AtomicInteger n = new AtomicInteger(0);
    public Producer(String str,int i,Fifo f) ....
    
    public void run() {
        try {
            this.go();
        } catch (InterruptedException e) {
            ;
        }
    }
    
    void go() throws InterruptedException {
        while(true) {
                Thread.sleep(i);
                // 原子操作:先获取当前值再自增,等价原有n++的逻辑
                int l = n.getAndIncrement();
                String k=str+" "+l+" ";
                f.put(k);
            System.out.println("produced "+str+" "+l+" "+System.currentTimeMillis()%100000);
        }
    }

}

方案2:对自增操作加互斥锁(实现简单,适合并发量不高的场景)

通过synchronized关键字对自增逻辑加锁,保证同一时间只有一个线程能执行自增操作,避免并发冲突,代码示例:

public class Producer implements Runnable{
    private String str;
    private Fifo f;
    private int i;
    private static volatile int n=0;
    // 定义全局锁对象
    private static final Object COUNT_LOCK = new Object();
    public Producer(String str,int i,Fifo f) ....
    
    public void run() {
        try {
            this.go();
        } catch (InterruptedException e) {
            ;
        }
    }
    
    void go() throws InterruptedException {
        while(true) {
                Thread.sleep(i);
                int l;
                // 加锁保证自增操作原子性
                synchronized (COUNT_LOCK) {
                    l = n++;
                }
                String k=str+" "+l+" ";
                f.put(k);
            System.out.println("produced "+str+" "+l+" "+System.currentTimeMillis()%100000);
        }
    }

}

方案3:使用LongAdder类(JDK1.8+适用,超高并发场景性能更优)

如果生产环境并发量极高,可以使用LongAdder替换AtomicInteger,它通过分段计数的方式降低CAS操作的竞争频率,高并发场景下性能优于AtomicInteger。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 07:09:04