基于分区属性的Java对象锁实现方案咨询
按Car的partition属性实现分组同步的方案
一、使用Map<String, Object>的可行实现
可以用线程安全的Map存储每个partition对应的锁对象,核心逻辑是同一个partition值对应同一个锁实例,不同partition对应不同锁,以此实现同组同步、异组并行的效果。
具体代码实现:
// 必须用线程安全的ConcurrentHashMap,规避多线程并发问题 private final ConcurrentHashMap<String, Object> partitionLocks = new ConcurrentHashMap<>(); private Object getLock(Car car) { String partitionKey = car.partition; // putIfAbsent保证同一个partition只会创建一个锁对象 partitionLocks.putIfAbsent(partitionKey, new Object()); return partitionLocks.get(partitionKey); }
但这种方式存在明显缺陷:锁对象会被Map永久持有引用,无法被GC回收,如果partition值数量过多或频繁新增,会引发内存泄漏问题。
二、更优解决方案:带自动回收的缓存实现
为解决内存泄漏问题,推荐使用支持自动过期回收的缓存管理锁对象,比如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; import java.util.concurrent.TimeUnit; // 初始化缓存,设置5分钟未访问则自动回收锁对象 private final LoadingCache<String, Object> lockCache = CacheBuilder.newBuilder() .expireAfterAccess(5, TimeUnit.MINUTES) .build(new CacheLoader<String, Object>() { @Override public Object load(String partitionKey) { // 每个partition对应一个独立锁对象 return new Object(); } }); private Object getLock(Car car) { try { // 自动加载或获取已有锁对象 return lockCache.get(car.partition); } catch (ExecutionException e) { throw new RuntimeException("获取锁对象失败", e); } }
如果不想引入Guava依赖,也可以用WeakHashMap替代,但需注意:WeakHashMap的键是弱引用,仅当partition字符串无其他强引用时才会被GC回收。若partition值来自字符串常量池(比如硬编码字符串),则键不会被回收,WeakHashMap无法解决内存泄漏,这种场景下仍推荐使用带过期机制的缓存方案。
三、核心逻辑总结
无论采用哪种方式,核心都是让相同partition的Car实例获取同一个锁对象。相比基础的ConcurrentHashMap,带自动回收的缓存方案更适合生产环境,能有效避免内存占用过高的问题。
内容的提问来源于stack exchange,提问作者Maayan Hope
相关产品推荐
相关产品推荐

