当前位置: 首页
编程语言
多线程环境安全读取及替换只读列表方法

多线程环境安全读取及替换只读列表方法

热心网友 时间:2026-07-11
转载

使用volatile或AtomicReference配合不可变列表,替代synchronized实现无锁读取与原子更新,消除锁竞争,提升读吞吐量。前提是不可变性,需用List copyOf()封装避免并发修改。

本文介绍一种比 synchronized 更轻量、更高性能的线程安全解决方案:利用 volatile 或 AtomicReference 取代传统的同步方法,结合不可变列表(例如 List.copyOf()),实现无锁读取与原子更新操作。

在高并发的生产环境中,频繁使用 synchronized 方法会导致显著的性能损耗和可伸缩性瓶颈。你目前的代码中,getFoo() 和 refresh() 均被 synchronized 修饰,但实际业务场景非常清晰:读取操作不涉及状态修改,写入操作仅整体替换列表——这完全符合“不可变发布”(immutable publication)模型,完全没有必要使用重量级锁。

✅ 推荐方案:volatile + 不可变列表

由于 list 始终通过整体赋值方式更新(不存在原地修改),并且所有读取操作都在赋值完成后进行,volatile 字段足以提供所需的 happens-before 保证:新列表的构建与发布,对所有线程均立即可见。

private volatile List list = List.of(); // 初始化为空不可变列表

public Foo getFoo(Condition condition) {
    // 无需同步:volatile 保证读到最新引用,且列表本身不可变
    for (Foo foo : list) {
        if (condition.check(foo)) {
            return foo;
        }
    }
    return null;
}

public void refresh() {
    // fetchFromDB() 返回新列表;用 List.copyOf() 强制不可变
    List newList = List.copyOf(fetchFromDB());
    list = newList; // volatile 写入,对所有线程立即可见
}

? 注意:List.copyOf()(Java 10+)不仅会创建不可变副本,还会在运行时检查源列表是否被意外修改(抛出 UnsupportedOperationException),因此比 Collections.unmodifiableList() 更加安全可靠。

? 备选方案:AtomicReference>

如果你需要支持更复杂的原子操作(例如 CAS 更新或条件刷新),可以考虑采用 AtomicReference:

private final AtomicReference> listRef = new AtomicReference<>(List.of());

public Foo getFoo(Condition condition) {
    for (Foo foo : listRef.get()) { // get() 具有 volatile 读语义
        if (condition.check(foo)) {
            return foo;
        }
    }
    return null;
}

public void refresh() {
    List newList = List.copyOf(fetchFromDB());
    listRef.set(newList); // set() 具有 volatile 写语义
}

⚠️ 关键注意事项

  • 不可变是核心前提:list 引用所指向的对象必须不可被修改。如果 fetchFromDB() 返回的是可变 ArrayList,必须使用 List.copyOf() 或 Collections.unmodifiableList() 进行封装;否则,其他线程在遍历时可能遇到 ConcurrentModificationException 或数据不一致问题。
  • 元素本身也需要线程安全:Foo 实例自身不应包含共享可变状态;如果内部存在状态,必须确保其线程安全性(例如使用 final 字段、不可变设计或同步访问机制)。
  • 防范隐式修改:切勿将 list 赋值给非 final 的可变变量后再进行修改(例如 List temp = list; temp.add(...)),这将彻底破坏线程安全性。
  • 文档即契约:在字段声明旁添加明确注释:
    // Thread-safe: list is volatile and always points to an unmodifiable List.
    // Never mutate the list or its elements after assignment.
    private volatile List list = List.of();

✅ 总结

相较于 synchronized,volatile 方案彻底消除了锁竞争,显著提升了读取吞吐量;同时结合 List.copyOf() 确保不可变语义,从源头上杜绝了并发修改的风险。该模式简洁、高效、易于测试,堪称“只读+全量更新”场景的最佳实践。

来源:https://www.php.cn/faq/2790437.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
IDEA中SpringBoot项目热部署实现指南

IDEA中SpringBoot项目热部署实现指南

Springboot项目在IDEA中实现热部署需依次完成:开启自动编译(静态与动态编译)、启用热部署策略、引入spring-boot-devtools依赖、关闭浏览器缓存,最后启动测试即可生效,省去手动重启时间,大幅提升开发效率。

时间:2026-07-11 06:47
Java实现Excel转JSON的代码详解

Java实现Excel转JSON的代码详解

使用Java结合FreeSpire XLS库可自动将Excel转为JSON,通过读取工作表并映射为键值对,高效支持数据迁移、报表导出与系统对接,大幅提升效率并消除手动录入错误。

时间:2026-07-11 06:47
Golang高效布谷鸟过滤器多字符集字符串过滤

Golang高效布谷鸟过滤器多字符集字符串过滤

布谷鸟过滤器支持删除操作,通过指纹截断与双哈希定位实现多字符集高效过滤。指纹截断需采用fnv64a或xxhash快速哈希并取低8位,桶索引使用独立双哈希避免假阳性。并发安全需以固定数组配合sync atomic实现。

时间:2026-07-11 06:47
Java使用Poi-tl按Word模板生成动态表格

Java使用Poi-tl按Word模板生成动态表格

Poi-tl是Word导出工具,文档周全,支持多级合并表头生成。通过{{text}}、{{?var}}、{{ table}}标签处理模板,传入TableRenderData对象即可动态渲染表格。示例展示用户信息表格生成,并提供工具类消除表格首行缩进,确保格式正确。

时间:2026-07-11 06:47
Go语言微服务集成Swagger生成交互式API文档完整教程

Go语言微服务集成Swagger生成交互式API文档完整教程

在Go微服务中集成Swagger常见四大问题:swaginit初始化失败需确保存在packagemain及注释;SwaggerUI加载失败因路由映射错误或未导入docs;@Param注解必须严格遵循格式;部署后接口文档显示localhost因硬编码host,应删除或通过环境变量动态注入。

时间:2026-07-11 06:47
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜