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

Java读写并发:Lock+Volatile与ReadWriteLock的性能及生产选型

读多写少场景下的并发方案对比:吞吐量与生产选型

问题背景

假设读操作的数量是写操作的10倍,从吞吐量角度来看,以下两种并发方案哪种更优?生产代码中应选用哪种方案?

方案1:写操作加锁,读操作使用volatile变量

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public final class InstanceProvider {

    private final Lock wLock = new ReentrantLock();
    private volatile List<Instance> instances;

    public void setInstances(List<Instance> newInstances) {
        wLock.lock();
        try {
            doSmthWith(newInstances);
            instances = newInstances;
        } finally {
            wLock.unlock();
        }
    }

    public List<Instance> getInstances() {
        return instances;
    }

    @Getter
    public static final class Instance {

        private final String name;

        public Instance(String name) {
            this.name = name;
        }

    }
}

方案2:读写操作使用ReadWriteLock

import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public final class InstanceProvider {

    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private List<Instance> instances;

    public void setInstances(List<Instance> newInstances) {
        lock.writeLock().lock();
        try {
            doSmthWith(newInstances);
            instances = newInstances;
        } finally {
            lock.writeLock().unlock();
        }
    }

    public List<Instance> getInstances() {
        lock.readLock().lock();
        try {
            return instances;
        } finally {
            lock.readLock().unlock();
        }
    }

    @Getter
    public static final class Instance {

        private final String name;

        public Instance(String name) {
            this.name = name;
        }

    }
}

我的假设:读取volatile变量的成本更低(通常大部分时间会被缓存),而锁需要执行额外的指令。


吞吐量对比

从吞吐量角度看,方案1的表现会更优,原因如下:

  • 方案1的读操作直接读取volatile变量,volatile的读操作开销极低:它仅保证变量的可见性,无需线程阻塞或复杂的锁指令,大部分情况下变量会被CPU缓存命中,几乎无额外开销。
  • 方案2的读操作需要获取/释放读锁,尽管ReentrantReadWriteLock的读锁支持多线程并发持有,但加锁解锁过程仍涉及CAS操作、内存屏障等指令,在读操作是写操作10倍的读密集场景下,大量读锁操作的累积开销会显著高于volatile读,拉低整体吞吐量。

生产代码选型建议

生产环境中不能只看吞吐量,还要结合线程安全要求和业务场景:

优先选方案1的场景

如果满足以下条件,方案1是更优选择:

  • 返回的List<Instance>是不可变对象(比如调用setInstances时传入Collections.unmodifiableList包装后的列表,或者Instance本身是不可变类且列表不会被外部修改);
  • 业务仅需要保证instances引用的可见性,无需在读操作期间阻止写操作(即允许读操作看到最新的写结果即可,不需要读操作期间数据绝对稳定)。

这种场景下,方案1既保证了线程安全,又能最大化吞吐量。

优先选方案2的场景

如果存在以下情况,方案2更合适:

  • 返回的List<Instance>可能被外部修改,或者需要在读操作期间保证数据的一致性(比如读操作过程中不允许写操作修改instances引用);
  • 业务需要更严格的线程安全保障,比如避免读操作读到半初始化的对象(虽然方案1中volatile也能避免这种情况,但读锁可以提供更强的互斥语义)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:51:12