3

我有一个 Singleton 类处理一种在 Hashmap 中具有不同对象的缓存。(键的格式直接链接到存储在映射中的对象类型 - 因此映射是 )

地图上可能有三种不同的操作:添加、获取、删除。

我使用公共入口点方法(无密集访问)保护了对地图的访问:

public synchronized Object doAction(String actionType, String key, Object data){
  Object myObj = null;
  if (actionType.equalsIgnorecase("ADD"){
    addDataToMyMap(key,data);
  } else if (actionType.equalsIgnorecase("GET"){
    myObj = getDataFromMyMap(key);
  } else if (actionType.equalsIgnorecase("REM"){  
    removeDataFromMyMap(key);      
  }
  return myObj;
}

笔记:

地图是私人的。方法 addDataToMyMap()、getDataFromMyMap() 和 removeDataFromMyMap() 是私有的。只有入口点方法是公共的,除了类本身的静态 getInstance() 之外别无其他。

您是否确认并发访问地图是线程安全的,因为除了通过该方法之外没有其他方法可以使用地图?

如果地图是安全的,我想这个原则可以应用于任何其他类型的共享资源。

非常感谢您的回答。

大卫

4

8 回答 8

1

我需要看看你的方法的实现,但这可能就足够了。但是我建议您使用 Java 的 Collection API 中的 Map,那么除非您共享其他实例,否则您不需要同步您的方法。

阅读:http ://www.java-examples.com/get-synchronized-map-java-hashmap-example

于 2012-07-13T14:21:01.753 回答
1

是的,只要唯一的入口点是 doAction,您的类将是线程安全的。

于 2012-07-13T14:21:52.407 回答
1

如果你的cache类是私有的HashMap,并且你有三个方法,并且所有方法都是私有的,如果你没有任何其他public synchronized实例变量,那么我认为你的缓存是.staticpublicthread-safe

最好发布您的代码。

于 2012-07-13T14:22:34.683 回答
1

这是完全安全的。只要所有线程都使用公共锁访问它,在这种情况下是对象,那么它就是线程安全的。(其他答案可能性能更高,但您的实施是安全的。)

于 2012-07-13T14:33:20.420 回答
0

您可以使用Collections.synchronizedMap来同步对Map.

于 2012-07-13T14:21:44.450 回答
0

因为很难确定代码是否是线程安全的。您的示例中缺少的重要信息是:

  1. 方法是否公开
  2. 方法是否同步
  3. 它的地图只能通过方法访问

我建议您研究同步以了解问题以及如何解决这些问题。探索ConcurrentHashMap类将提供有关您的问题的更多信息。

于 2012-07-13T14:27:47.420 回答
0

您应该使用ConcurrentHashMap。它提供比同步的 doAction 更好的吞吐量和比 Collections.synchronizedMap() 更好的线程安全性。

于 2012-07-13T14:30:15.023 回答
0

这取决于您的代码。正如其他人所说,您可以使用 Collections.synchronizedMap。但是,这只会同步地图上的各个方法调用。因此,如果:

map.get(key);
map.put(key,value);

在两个不同的线程中同时执行,一个会阻塞,直到另一个退出。但是,如果您的关键部分大于对地图的单个调用:

SomeExpensiveObject value = map.get(key);
if (value == null) {
   value = new SomeExpensiveObject();
   map.put(key,value);
}

现在让我们假设密钥不存在。第一个线程执行,并返回一个空值。调度程序产生该线程,并运行线程 2,该线程也返回一个空值。它构造新对象并将其放入地图中。然后线程 1 恢复并执行相同的操作,因为它仍然有一个空值。

这是您希望在关键部分周围有一个更大的同步块的地方

SomeExpensiveObject value = null;

synchronized (map) {
  value = map.get(key);
  if (value == null) {
     value = new SomeExpensiveObject();
     map.put(key,value);
  }
}
于 2012-07-16T13:42:03.327 回答