在 Java 中使用 Map 的线程安全静态可变 Map
Using a thread safe static mutable Map of Map in Java
我需要添加一个静态线程安全的 HashMap。我有这样的东西 -
private static Map<String, ConcurrentHashMap<Integer, ClassA>> myCache =
new ConcurrentHashMap<String, ConcurrentHashMap<Integer, ClassA>>();
即使我正在使用 ConcurrentHashMap,我发现如果主线程正在 myCache 中添加元素,并且即使稍后在其他线程中访问相同的元素,它myCache 对象中没有最新数据。例如
线程 1:向地图添加条目
myCache = {a1={1=com.x.y.z.ClassA@3ec8b657}}
线程 2:访问相同的键 a1
。但它看不到线程 1 添加的数据。相反,它看到此键的空值 myCache = {a1={}}
结果,数据被破坏。在线程 1 中为 a1
键添加的条目在线程 2 中不可见。
提前感谢您提供有关如何以线程安全方式更新此地图的任何指示。
我从来没有用 ConcurrentHashMap 取得过好的结果。当我需要线程安全时,我通常会这样做:
public class Cache<K, V> {
private Map<K, V> cache = new HashMap<>();
public V get(K key) {
synchronized (cache) {
return cache.get(key);
}
}
public void put(K key, V value) {
synchronized(cache) {
cache.put(key, value);
}
}
}
@Ryan 的回答基本上是正确的。
请记住,您必须代理您希望使用的每个 Map
方法
并且您必须同步到每个代理方法中的 cashe
元素。
例如:
public void clear()
{
synchronized(cache)
{
cache.clear();
}
}
Even though I am using ConcurrentHashMap, I see that if main thread is adding element in the myCache, and when the same is accessed in other thread even at later time, it does not have the latest data in the myCache object.
ConcurrentHashMap
是 运行 在世界各地的大量应用程序中。如果您相当典型的用例不能正常工作,许多关键系统就会失败。
发生了一些事情,但很可能与 ConcurrentHashMap
无关。所以这里有一些问题可以帮助您调试代码:
- 您确定缓存查找发生在缓存放置之后?
ConcurrentHashMap
不会使您免于代码中的竞争条件。
- 这是否可能是关键对象的
hashcode()
或 equals()
函数的问题?默认情况下,hashcode()
和 equals()
方法用于对象 实例 而不是对象值。见 consistency requirements.
- 是否有可能在缓存删除或缓存值超时后发生缓存查找?是否有缓存清理逻辑?
- 你有在
ConcurrentHashMap
上执行 2 个操作的逻辑吗?例如,测试缓存条目是否存在,然后再次调用以放置该值?如果是这样,您应该使用 putIfAbsent(...)
或其他原子调用。
如果您编辑 post 并显示带有密钥对象的 小型 代码示例,则可能会揭示问题的真正根源。
我需要添加一个静态线程安全的 HashMap。我有这样的东西 -
private static Map<String, ConcurrentHashMap<Integer, ClassA>> myCache =
new ConcurrentHashMap<String, ConcurrentHashMap<Integer, ClassA>>();
即使我正在使用 ConcurrentHashMap,我发现如果主线程正在 myCache 中添加元素,并且即使稍后在其他线程中访问相同的元素,它myCache 对象中没有最新数据。例如
线程 1:向地图添加条目
myCache = {a1={1=com.x.y.z.ClassA@3ec8b657}}
线程 2:访问相同的键 a1
。但它看不到线程 1 添加的数据。相反,它看到此键的空值 myCache = {a1={}}
结果,数据被破坏。在线程 1 中为 a1
键添加的条目在线程 2 中不可见。
提前感谢您提供有关如何以线程安全方式更新此地图的任何指示。
我从来没有用 ConcurrentHashMap 取得过好的结果。当我需要线程安全时,我通常会这样做:
public class Cache<K, V> {
private Map<K, V> cache = new HashMap<>();
public V get(K key) {
synchronized (cache) {
return cache.get(key);
}
}
public void put(K key, V value) {
synchronized(cache) {
cache.put(key, value);
}
}
}
@Ryan 的回答基本上是正确的。
请记住,您必须代理您希望使用的每个 Map
方法
并且您必须同步到每个代理方法中的 cashe
元素。
例如:
public void clear()
{
synchronized(cache)
{
cache.clear();
}
}
Even though I am using ConcurrentHashMap, I see that if main thread is adding element in the myCache, and when the same is accessed in other thread even at later time, it does not have the latest data in the myCache object.
ConcurrentHashMap
是 运行 在世界各地的大量应用程序中。如果您相当典型的用例不能正常工作,许多关键系统就会失败。
发生了一些事情,但很可能与 ConcurrentHashMap
无关。所以这里有一些问题可以帮助您调试代码:
- 您确定缓存查找发生在缓存放置之后?
ConcurrentHashMap
不会使您免于代码中的竞争条件。 - 这是否可能是关键对象的
hashcode()
或equals()
函数的问题?默认情况下,hashcode()
和equals()
方法用于对象 实例 而不是对象值。见 consistency requirements. - 是否有可能在缓存删除或缓存值超时后发生缓存查找?是否有缓存清理逻辑?
- 你有在
ConcurrentHashMap
上执行 2 个操作的逻辑吗?例如,测试缓存条目是否存在,然后再次调用以放置该值?如果是这样,您应该使用putIfAbsent(...)
或其他原子调用。
如果您编辑 post 并显示带有密钥对象的 小型 代码示例,则可能会揭示问题的真正根源。