Java 无锁方式实现高性能线程

news/2025/10/19 16:17:43/文章来源:https://www.cnblogs.com/qz85784989/p/19150993

一、传统单例实现的局限性

在现代高并发Java应用中,传统的单例实现方式(如DCL双重检查锁定)虽然解决了线程安全问题,但仍存在以下局限性:

  1. 依赖锁机制(synchronized)导致上下文切换开销
  2. volatile关键字在某些JVM实现中的性能差异
  3. 反射攻击和序列化问题
  4. 初始化时机不够灵活
  5. 无法利用现代硬件的并发特性

二、现代无锁单例实现方案

1. 基于ThreadLocal的延迟初始化单例
public class ThreadLocalSingleton {private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = ThreadLocal.withInitial(ThreadLocalSingleton::new);private ThreadLocalSingleton() {// 私有构造函数}public static ThreadLocalSingleton getInstance() {return threadLocalInstance.get();}// 清理线程局部变量,避免内存泄漏public static void remove() {threadLocalInstance.remove();}
}
 
 

优势

  • 每个线程拥有独立的实例,减少了线程间竞争
  • 无需显式同步,避免了锁带来的性能开销
  • 实现了延迟初始化

适用场景

  • 线程上下文相关的单例对象
  • 需要在每个线程中维护独立状态的场景
2. 使用VarHandle实现的原子单例
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;public class VarHandleSingleton {private static final VarHandle INSTANCE;private static VarHandleSingleton instance;static {try {MethodHandles.Lookup l = MethodHandles.lookup();INSTANCE = l.findStaticVarHandle(VarHandleSingleton.class, "instance", VarHandleSingleton.class);} catch (ReflectiveOperationException e) {throw new ExceptionInInitializerError(e);}}private VarHandleSingleton() {// 私有构造函数}public static VarHandleSingleton getInstance() {VarHandleSingleton result = (VarHandleSingleton) INSTANCE.getAcquire();if (result != null) {return result;}result = new VarHandleSingleton();if (INSTANCE.compareAndSet(null, result)) {return result;}return (VarHandleSingleton) INSTANCE.getAcquire();}
}
 
 

优势

  • Java 9引入的VarHandle提供了比AtomicReference更底层的原子操作
  • 支持不同的内存排序语义(如getAcquire/setRelease)
  • 性能优于传统的Atomic实现

适用场景

  • 需要精细控制内存语义的高性能场景
  • 对CAS操作有更高性能要求的应用
3. 使用Record类的不可变单例
import java.util.concurrent.atomic.AtomicReference;public record RecordSingleton(String config) {private static final AtomicReference<RecordSingleton> INSTANCE = new AtomicReference<>();public static RecordSingleton getInstance() {return INSTANCE.updateAndGet(current -> current != null ? current : new RecordSingleton("defaultConfig"));}// 可选:提供配置更新方法public static RecordSingleton updateConfig(String newConfig) {return INSTANCE.updateAndGet(current -> current != null ? new RecordSingleton(newConfig) : new RecordSingleton(newConfig));}
}
 
 

优势

  • Java 14引入的Record类提供了不可变数据结构
  • 简洁的语法和自动生成的方法
  • 线程安全的不可变对象

适用场景

  • 配置管理类单例
  • 数据传输对象(DTO)单例
4. 响应式单例模式(结合Reactor)
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;public class ReactiveSingleton {private static final Mono<ReactiveSingleton> INSTANCE = Mono.fromCallable(ReactiveSingleton::new).subscribeOn(Schedulers.boundedElastic()).cache(); // 缓存结果,确保只创建一次private ReactiveSingleton() {// 私有构造函数// 模拟耗时初始化try {Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}public static Mono<ReactiveSingleton> getInstance() {return INSTANCE;}// 示例方法public Mono<String> process(String data) {return Mono.just(data.toUpperCase());}
}
 
 

优势

  • 非阻塞异步初始化
  • 背压支持
  • 响应式编程范式
  • 内置线程池管理

适用场景

  • 微服务架构中的单例组件
  • 需要异步处理的单例服务
  • 响应式系统中的共享资源
5. 基于CDI的依赖注入单例
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Singleton;@Singleton // 或使用 @ApplicationScoped (Jakarta EE)
public class CdiSingleton {private int counter = 0;public synchronized int incrementAndGet() {return ++counter;}// 业务方法public String doBusinessLogic() {return "Business logic executed with counter: " + counter;}
}
 
 

优势

  • 容器管理生命周期
  • 依赖注入支持
  • 与Java EE/Quarkus/MicroProfile等框架集成良好
  • 内置线程安全保证

适用场景

  • 企业级Java应用
  • 基于Jakarta EE/Quarkus的微服务
  • 需要声明式事务和安全的场景

三、现代无锁单例的性能测试

以下是使用JMH框架进行的性能测试代码示例:

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;import java.util.concurrent.TimeUnit;@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(1)
@State(Scope.Benchmark)
public class SingletonBenchmark {@Benchmarkpublic void enumSingleton(Blackhole bh) {bh.consume(EnumSingleton.INSTANCE);}@Benchmarkpublic void staticInnerClassSingleton(Blackhole bh) {bh.consume(StaticInnerClassSingleton.getInstance());}@Benchmarkpublic void varHandleSingleton(Blackhole bh) {bh.consume(VarHandleSingleton.getInstance());}@Benchmarkpublic void recordSingleton(Blackhole bh) {bh.consume(RecordSingleton.getInstance());}@Benchmarkpublic void reactiveSingleton(Blackhole bh) throws Exception {ReactiveSingleton.getInstance().block(); // 实际应用中应使用响应式方式处理}public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(SingletonBenchmark.class.getSimpleName()).build();new Runner(opt).run();}
}
 
 

典型的测试结果表明,在高并发场景下,基于VarHandle的实现通常比传统的DCL和枚举单例有5-10%的性能提升,而响应式单例在异步场景下表现最佳。

四、应用实例:高性能配置中心

下面是一个结合多种现代技术的高性能配置中心实现:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;public class ConfigCenter {// 使用AtomicReference确保无锁更新private static final AtomicReference<ConfigCenter> INSTANCE = new AtomicReference<>();// 使用ConcurrentHashMap存储配置项private final Map<String, Object> configs = new ConcurrentHashMap<>();// 私有构造函数private ConfigCenter() {// 从配置源加载初始配置loadDefaultConfigs();}// 无锁单例获取方法public static ConfigCenter getInstance() {return INSTANCE.updateAndGet(current -> current != null ? current : new ConfigCenter());}// 加载默认配置private void loadDefaultConfigs() {// 从文件、数据库或远程服务加载配置configs.put("app.name", "HighPerformanceApp");configs.put("max.connections", 100);configs.put("timeout.seconds", 30);}// 获取配置项@SuppressWarnings("unchecked")public <T> T getConfig(String key) {return (T) configs.get(key);}// 获取配置项,不存在时使用默认值@SuppressWarnings("unchecked")public <T> T getConfig(String key, T defaultValue) {return (T) configs.getOrDefault(key, defaultValue);}// 动态配置获取,支持延迟初始化@SuppressWarnings("unchecked")public <T> T getConfig(String key, Supplier<T> defaultSupplier) {return (T) configs.computeIfAbsent(key, k -> defaultSupplier.get());}// 更新配置public void updateConfig(String key, Object value) {configs.put(key, value);}// 批量更新配置public void updateConfigs(Map<String, Object> newConfigs) {configs.putAll(newConfigs);}
}
 
 

这个配置中心实现了:

  1. 无锁方式的单例创建
  2. 线程安全的配置存储(使用ConcurrentHashMap)
  3. 动态配置加载
  4. 延迟初始化支持
  5. 高性能的配置读取和更新

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/940415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用 【C# + Winform + MediaPipe】 构建人脸468点识别

用 【C# + Winform + MediaPipe】 构建人脸468点识别2025-10-19 16:14 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; dis…

10.19日模考总结

本周进行了标准OI普及组模考测试 得分情况题目名称 做法 预计得分 实际得分火车线路 模拟 100 100奶牛卧室 同余定理 100 70小信的同调序列 动态规划 10 30新小信走迷宫 贪心、动态规划 20 40做题流程 首先点开第一题,…

详细介绍:2020年美国新冠肺炎疫情数据分析与可视化

详细介绍:2020年美国新冠肺炎疫情数据分析与可视化pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

java流程控制。

用户交互Scanner之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入。java.util.Scanner 是Java5 的新特征,我们可以通过Scanner 类来获取用户的输入…

mysql嵌套查询如何利用索引?

SELECT foreach_id FROM zyp_作业计划 where jtPlanKey = 2000000507162 --jtPlanKey 为主键 ,int64类型,foreach_id 为varcharSELECT OnLineVidio FROM jobbill where foreach_id =‘731221717606469’ …

Misaka2298 的写题自检表

数据范围看了吗?会爆 int 吗?会爆 longlong 吗? debug 删完了吗? freopen 写了吗? 题目真的读懂了吗?数据范围有漏看吗? 有时间写对拍吗?对拍好写吗?是应该继续冲还是应该写拍子呢? 会爆内存吗?检查空间占用…

解码Linux文件IO之LCD屏原理及应用

LCD 基本概念与结构 核心定义 LCD(Liquid Crystal Display)即液晶显示器,核心是通过液晶分子的电光效应控制光线透过,结合光学组件实现图像显示。其基本构造是在两片平行玻璃基板间夹着液晶盒,关键组件分工如下:…

2025年扑灭司林厂家推荐排行榜,高效环保扑灭司林,专业生产与市场口碑深度解析!

2025年扑灭司林厂家推荐排行榜:高效环保扑灭司林,专业生产与市场口碑深度解析随着环保意识的不断增强,高效环保的扑灭司林产品越来越受到市场的青睐。扑灭司林作为一种重要的农药成分,在农业、林业以及公共卫生领域…

微信小程序入门学习教程,从入门到精通,WXML(WeiXin Markup Language)语法基础(8) - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Java 中 NullPointerException 的 3 个常见原因及解决

空指针是 Java 最常见异常,主要因 “调用了 null 对象的方法 / 属性”,常见场景:​ 对象没初始化就用(如User u = null; u.getName()),解决:先u = new User();​ 方法返回 null 没判断(如String s = getStrin…

Java 方法参数传递:到底是值传递还是引用传递?

结论:只有值传递!很多人误解引用类型是 “引用传递”,其实是传递了 “引用的副本(地址值)”。​ 比如传 int 时,复制值给方法参数,修改参数不影响原变量;传对象时,复制地址给参数,若修改参数指向的对象内容(…

ES6 箭头函数

引言ES6 箭头函数(=>)彻底改变了 JavaScript 的编码风格,提供简洁语法和词法作用域绑定。但不当使用可能引发意外行为,本文将揭示其核心特性和避坑指南。1. 词法绑定 this:告别 bind 箭头函数继承外层 this,解决…

centos 7.9快速部署ARL(Asset Reconnaissance Lighthouse)资产侦察灯塔系统用于信息收集

github项目地址:https://github.com/honmashironeko/ARL-docker #感谢项目作者做出的贡献如果git下载不了,下载zip包 通过网盘分享的文件:ARL-docker-main.zip 链接: https://pan.baidu.com/s/1lF3EBWCkJHjW0P9Irf…

3 分钟搞懂 Java 中 this 关键字的用法

Java 里 this 常被初学者忽略,其实就两个核心作用:一是区分成员变量和局部变量,比如构造方法中this.name = name,避免变量名冲突;二是调用本类其他构造方法,用this(参数)在构造方法首行调用,减少重复代码。​ 示…

折腾笔记[32]-windows部署vscode-server及使用命令行编译c#.net工程

工控机windows双击exe一键运行vscode-server及使用命令行编译c#.net工程.摘要 工控机windows双击exe一键运行vscode-server及使用命令行编译c#.net工程. 1. 一键运行code-server 下载地址:[https://gitee.com/David-Co…

Java 中 ArrayList 和 LinkedList 的选择技巧

日常开发选集合常纠结,记住两个关键场景:​ 若频繁做 “查询”(比如get(index)),选 ArrayList,底层数组支持随机访问,速度快;若频繁做 “增删”(尤其是中间位置),选 LinkedList,底层链表只需改指针,不用像…

Java 静态方法为什么不能访问非静态成员?

很多人疑惑静态方法里调非静态变量会报错,核心原因是 “加载时机不同”:静态成员(方法 / 变量)在类加载时就初始化,属于 “类级别的资源”;非静态成员要等创建对象后才存在,属于 “对象级别的资源”。​ 就像没…

ES6 箭头函数:告别 `this` 的困扰

ES6 箭头函数:告别 this 的困扰 引言ES6 箭头函数(=>)不仅是语法糖,更解决了 JavaScript 中 this 绑定的核心痛点。本文将揭示其四大实战价值,助你写出更简洁可靠的代码。1. 极简语法:告别 function 冗余 单参…

2025润滑油厂家推荐:三特石化全合成长效发动机油,品质卓越!

2025润滑油厂家推荐:三特石化全合成长效发动机油,品质卓越!随着工业和汽车行业的快速发展,对润滑油的需求不断增加。润滑油作为机械设备运行的重要保障,其质量和性能直接影响到设备的使用寿命和工作效率。本文将深…

Java 类与对象实践:从代码验证到四则运算开发

Java类与对象实践:从代码验证到四则运算开发 在学习Java类与对象后,通过代码验证课件知识点、完成四则运算开发,能更深入理解面向对象编程思想。以下是我在实践过程中的详细记录,包含知识点验证、问题解决及项目开…