Java线程安全单更新方案咨询:AtomicReference适用性及示例需求
多线程下单次对象更新实现方案
基于AtomicReference的实现
使用AtomicReference的updateAndGet方法可完美满足需求——该方法通过CAS(Compare-And-Swap)机制保证原子性,确保只有一个线程能执行对象更新逻辑,其他线程直接复用更新后的实例。
代码示例
import java.util.concurrent.atomic.AtomicReference; // 模拟业务服务类 class Service { // 故障检测逻辑,根据实际场景实现 public boolean isFaulty() { // 示例:检查连接是否断开、服务是否超时等 return false; } // 创建新服务实例的方法,实际包含初始化资源、连接等逻辑 public static Service createNewService() { return new Service(); } } // 共享对象持有类 public class SharedServiceHolder { private final AtomicReference<Service> serviceRef = new AtomicReference<>(Service.createNewService()); public Service getService() { Service current = serviceRef.get(); // 检查当前实例是否故障 if (current.isFaulty()) { // 原子性更新:仅当当前引用未被其他线程修改时执行更新 Service updated = serviceRef.updateAndGet(s -> { // 二次检查,避免其他线程已完成更新 if (s.isFaulty()) { return Service.createNewService(); } return s; }); return updated; } return current; } }
关键说明
updateAndGet内部通过循环CAS实现,多个线程同时触发更新时,只有第一个成功CAS的线程会执行createNewService,其他线程直接获取已更新的实例。- 内部二次检查是必要的:避免当前线程获取
current后,其他线程已完成更新,此时无需重复创建实例。
基于Guava的实现
如果项目已依赖Guava,可使用LoadingCache实现,它内置原子加载逻辑,确保同一时间只有一个线程执行实例创建操作。
代码示例
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.concurrent.ExecutionException; class Service { public boolean isFaulty() { return false; } public static Service createNewService() { return new Service(); } } public class GuavaSharedServiceHolder { // 单实例缓存,使用固定key标识唯一实例 private final LoadingCache<String, Service> serviceCache = CacheBuilder.newBuilder() .build(new CacheLoader<String, Service>() { @Override public Service load(String key) { return Service.createNewService(); } }); public Service getService() throws ExecutionException { Service current = serviceCache.get("SINGLETON_SERVICE"); if (current.isFaulty()) { // 失效旧实例,触发重新加载 serviceCache.invalidate("SINGLETON_SERVICE"); // 重新获取新实例,LoadingCache保证原子加载 return serviceCache.get("SINGLETON_SERVICE"); } return current; } }
关键说明
LoadingCache的get方法保证:当多个线程同时请求未缓存的key时,只有一个线程会执行load方法创建实例,其他线程阻塞等待加载完成。- 调用
invalidate后,下一次get会触发新的加载,确保故障后仅创建一次新实例。
内容的提问来源于stack exchange,提问作者Olgun Kaya
相关产品推荐
相关产品推荐

