简体   繁体   English

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

[英]Is a java synchronized method entry point thread safe enough?

I have a Singleton class handling a kind of cache with different objects in a Hashmap. 我有一个Singleton类处理一种Hashmap中具有不同对象的缓存。 (The format of a key is directly linked to the type of object stored in the map - hence the map is of ) (键的格式直接链接到地图中存储的对象类型 - 因此地图是)

Three different actions are possible on the map : add, get, remove. 地图上可以执行三种不同的操作:添加,获取,删除。

I secured the access to the map by using a public entry point method (no intense access) : 我使用公共入口点方法(没有密集访问)来保护对地图的访问:

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;
}

Notes: 笔记:

The map is private. 地图是私人的。 Methods addDataToMyMap(), getDataFromMyMap() and removeDataFromMyMap() are private. 方法addDataToMyMap(),getDataFromMyMap()和removeDataFromMyMap()都是私有的。 Only the entry point method is public and nothing else except the static getInstance() of the class itself. 只有入口点方法是公共的,除了类本身的静态getInstance()之外别无其他。

Do you confirm it is thread safe for concurrent access to the map since there is no other way to use map but through that method ? 您是否确认并发访问地图是线程安全的,因为没有其他方法可以使用地图但通过该方法?

If it is safge for a Map, I guess this principle could be applied to any other kind of shared ressource. 如果它是Map的安全,我想这个原则可以应用于任何其他类型的共享资源。

Many thanks in advance for your answers. 非常感谢你的答案。

David 大卫

I would need to see your implementation of your methods, but it could be enough. 我需要看看你的方法的实现,但它可能就足够了。 BUT i would recommend you to use a Map from the Collection API of java then you wouldnt need to synchronize your method unless your sharing some other instance. 但我建议你使用java的Collection API中的Map,然后除非你共享其他实例,否则你不需要同步你的方法。

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

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

If your cache class has private HashMap and you have three methods and all are public synchronized and not static and if you don't have any other public instance variable then i think your cache is thread-safe . 如果您的cache类具有私有HashMap并且您有三个方法并且所有方法都是public synchronized而不是static并且如果您没有任何其他public实例变量,那么我认为您的缓存是thread-safe

Better to post your code. 最好发布您的代码。

This is entirely safe. 这是完全安全的。 As long as all the threads are accessing it using a common lock, which in this case is the Object, then it's thread-safe. 只要所有线程都使用公共锁访问它,在这种情况下是对象,那么它是线程安全的。 (Other answers may be more performant but your implementation is safe.) (其他答案可能更高效,但您的实施是安全的。)

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

As is it is hard to determine if the code is thread safe. 因为很难确定代码是否是线程安全的。 Important information missing from your example are: 您的示例中缺少的重要信息包括:

  1. Are the methods public 方法是否公开
  2. Are the methods synchronized 方法是否同步
  3. It the map only accessed through the methods 它只能通过方法访问地图

I would advice you to look into synchronization to get a grasp of the problems and how to tackle them. 我建议你研究同步 ,以掌握问题以及如何解决它们。 Exploring the ConcurrentHashMap class would give further information about your problem. 探索ConcurrentHashMap类将提供有关您的问题的更多信息。

You should use ConcurrentHashMap . 您应该使用ConcurrentHashMap It offers better throughput than synchronized doAction and better thread safety than Collections.synchronizedMap(). 与Collections.synchronizedMap()相比,它提供了比同步doAction更好的吞吐量和更好的线程安全性。

This depends on your code. 这取决于您的代码。 As someone else stated, you can use Collections.synchronizedMap. 正如其他人所说,您可以使用Collections.synchronizedMap。 However, this only synchronizes the individual method calls on the map. 但是,这只会同步地图上的各个方法调用。 So if: 因此,如果:

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

Are executed at the same time in two different threads, one will block until the other exits. 在两个不同的线程中同时执行,一个将阻塞,直到另一个退出。 However, if your critical section is larger than the single call into the map: 但是,如果您的关键部分大于对地图的单个调用:

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

Now let's assume the key is not present. 现在让我们假设密钥不存在。 The first thread executes, and gets a null value back. 第一个线程执行,并返回null值。 The scheduler yields that thread, and runs thread 2, which also gets back a null value. 调度程序产生该线程,并运行线程2,线程2也返回空值。 It constructs the new object and puts it in the map. 它构造新对象并将其放入地图中。 Then thread 1 resumes and does the same, since it still has a null value. 然后线程1恢复并执行相同的操作,因为它仍然具有空值。

This is where you'd want a larger synchronization block around your critical section 这是您需要围绕关键部分的更大同步块的地方

SomeExpensiveObject value = null;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM