我希望有一个类在多个线程的缓存中保存变量。
在ConcurrentHashMap中保存它是一个好习惯吗?
public class CacheMap {
private static Map<Object, Object> cacheMap = new ConcurrentHashMap<>();
public static void set(Object key, Object value) {
cacheMap.put(key, value);
}
public static Object get(String key) {
return cacheMap.get(key);
}
}
答案 0 :(得分:4)
在当前实现中,您可能会计算两次相同的值。我认为使用模式目前看起来像这样:
Object value = cache.get(key);
if(value == null) {
value = computeValue();
cache.set(key, value);
}
// use value here
如果有多个线程同时要求相同的值,那么如果有这样的代码,你可能会多次计算相同的值。此外,如果value
是长期存在的对象,它们将使用不同的结果对象,这可能导致不必要的内存浪费。
更好的解决方案是使用ConcurrentHashMap
的{{3}}方法:
Object value = map.computeIfAbsent(key, k -> computeValue());
这样一来,它保证每个键只计算一次。因此,我不建议在缓存实现中使用两个get
和set
方法,而是建议采用单computeIfAbsent
方法。
您的代码中也存在一些小问题,例如key
和get
方法中set
的不同类型以及缺少通用参数。
答案 1 :(得分:0)
我建议在volatile
中使用Map
,但其余模式似乎没问题。
来自this answer:
易失性变量:如果两个线程(假设t1和t2)正在访问同一个对象并更新一个声明为volatile的变量,则意味着t1和t2可以创建自己的本地缓存除了声明为volatile的变量之外的对象。所以volatile变量只有一个主副本,它将由不同的线程更新,一个线程对volatile变量的更新将立即反映到另一个Thread。
private volatile Map<Object, Object> cacheMap = new ConcurrentHashMap<>();
另外check this article了解更多信息。
答案 2 :(得分:-1)
在并发性方面,您的解决方案可以正常运行。 ConcurrentHashMap是线程安全的,因此它可以被许多线程使用。
我建议您小心内存泄漏,因为如果没有定义清理程序,缓存可以无限制地增长。
您也可以定义自己的缓存。例如,我喜欢为我的缓存对象使用LRU(最近最少使用)队列。使用LRU队列,您将确保缓存不会无限制地增长,并且将从缓存中删除的元素将是更久以前使用的元素。
您可以实现LRU队列,例如可能的实现可能是:
public class MyLRUHashMap<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = -3216599441788189122L;
private int maxCapacity = 1000;
protected MyLRUHashMap(int capacity) {
super(capacity);
maxCapacity = capacity;
}
protected MyLRUHashMap(int capacity, boolean accessOrder) {
super(capacity, 0.75f, accessOrder);
maxCapacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return (this.size() >= maxCapacity);
}
}
为了创建“MyHashMap”的线程安全变量,你必须以这种方式实例化它:
Map<Object, Object> MyCacheMap = Collections.synchronizedMap(new MyLRUHashMap(capacity, accessOrder));
希望它有所帮助! :)