【问题标题】:Synchronization of map object地图对象的同步
【发布时间】:2013-11-16 06:59:18
【问题描述】:

我有一个 Map 对象,它对应于存储在文件中的键值对。

private static Map myMap;

这个 Map 对象有一个管理器类,它有一个 getMap() 方法,该方法将对象返回给调用者。

public static Map getMap() 

它还有一个同步方法 saveMap() 将内容保存回文件

public static synchronized void saveMap(Map map)

问题在于,有些线程获取了 Map 对象但不想保存,即他们不调用 saveMap()。

假设 thread1 获取地图对象并对其进行修改,即向地图添加键值对。 key1=value1,一旦任务完成,从地图中删除这个键值对。在这之间有另一个线程 thread2 将另一个键值对添加到映射 key2=value2 并在 thread1 实际删除 之前保存它>key1 来自地图。这会导致 key1=value1 和 key2=value2 都保存到文件中。这不是我想要的。

我该如何克服这种情况?我正在考虑用

之类的方法修改 getMap() 方法
public Map getMap(boolean readonly) {
       if (readonly)
            return myMap.clone();
       return myMap;
}

这能解决我的问题吗?

注意:我不想使用互斥锁并锁定 Map 对象,因为我有长时间运行的进程会阻塞其他线程。

【问题讨论】:

  • 如果这不是你想要的,你为什么允许它发生?也许您应该将地图的 副本 提供给您不想保存其模组的线程。
  • @EJP 他提议的代码不就是这样吗?
  • 无论您在做什么,如果您有多个线程对地图进行修改,您的代码就不是线程安全的,并且迟早,地图将处于不一致的状态。您根本不应该公开地图。将其封装在您的类中,并同步每个对地图的访问。
  • ^+1^ 似乎要走的路。
  • @Sonic 一个鲜为人知的事实是,只有从一个线程读取地图,而另一个线程正在写入它,而两个线程都没有正确同步,可能会导致您的程序挂起!这是由于 HashMap 是如何实现的。

标签: java multithreading map synchronization


【解决方案1】:

我会做两件事之一。

我推荐的第一个是不要传递地图的副本。除了不使用同步对象的多线程问题之外,没有办法确保值不会因交错获取/保存而丢失/覆盖。

在您的管理器类中,删除 getMap() 和 saveMap(),并将它们替换为 getValue() 和 setValue()。我会让这些方法同步,或者用ConcurrentMap 替换 Map。这样一来,您就不会有人持有整个地图的实例。

第二个选项是将地图替换为Hashtable。这是同步和线程安全的,但速度较慢。这样可以解决您的一些问题,但不是全部。您仍然对围绕您的代码运行的地图有松散的引用。

【讨论】:

  • 谢谢。我会选择选项 1。干杯:)
  • 如果你想要一个同步的地图,不要使用旧的、过时的哈希表。使用Collections.synchronizedMap(anyMap)
  • @dj_segfault :如果我对每种方法都使用同步,是不是有死锁的机会?一些类级别的锁定对象对您来说更好吗?我的方法不是静态的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多