java同步方法入口点线程是否足够安全?

时间:2012-07-13 14:15:51

标签: java multithreading concurrency thread-safety shared-resource

我有一个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()之外别无其他。

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

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

非常感谢您的回答。

大卫

8 个答案:

答案 0 :(得分:1)

我需要看看你的方法的实现,但它可能就足够了。 但我建议你使用java的Collection API中的Map,然后除非你共享其他实例,否则你不需要同步你的方法。

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

如果您的cache班级设有私人HashMap且您有三种方法,且所有方法均为public synchronized而非static且您没有其他public然后我认为你的缓存是thread-safe

最好发布您的代码。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

您可以使用Collections.synchronizedMap来同步对Map的访问权限。

答案 5 :(得分:0)

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

  1. 方法是否公开
  2. 方法是否已同步
  3. 地图只能通过方法访问
  4. 我建议你研究synchronization以掌握问题以及如何解决这些问题。探索ConcurrentHashMap课程可以提供有关您的问题的更多信息。

答案 6 :(得分:0)

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

答案 7 :(得分: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);
}

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

这是您需要围绕关键部分的更大同步块的地方

SomeExpensiveObject value = null;

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