Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java同步方法入口点是否足够线程安全?_Java_Multithreading_Concurrency_Thread Safety_Shared Resource - Fatal编程技术网

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

java同步方法入口点是否足够线程安全?,java,multithreading,concurrency,thread-safety,shared-resource,Java,Multithreading,Concurrency,Thread Safety,Shared Resource,我有一个单例类,它在Hashmap中处理具有不同对象的缓存。 (键的格式直接链接到地图中存储的对象的类型-因此地图为) 在地图上可以执行三种不同的操作:添加、获取和删除 我通过使用公共入口点方法(无密集访问)确保了对地图的访问: 注: 这张地图是私人的。方法addDataToMyMap()、getDataFromMyMap()和removeDataFromMyMap()是私有的。只有入口点方法是公共的,除了类本身的静态getInstance()之外没有其他方法 您是否确认并发访问map是线程安全

我有一个单例类,它在Hashmap中处理具有不同对象的缓存。 (键的格式直接链接到地图中存储的对象的类型-因此地图为)

在地图上可以执行三种不同的操作:添加、获取和删除

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

注:

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

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

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

非常感谢您的回答


David

我需要看看您的方法的实现情况,但这就足够了。 但是我建议您使用java集合API中的映射,这样您就不需要同步您的方法,除非您共享其他实例


阅读以下内容:

您可以使用来同步对
映射的访问
是的,只要唯一的入口点是doAction,您的类将是线程安全的。

如果您的
缓存
类具有私有
哈希映射
,并且您有三个方法,并且所有方法都是
公共同步的
,而不是
静态的
如果没有任何其他
公共
实例变量,那么我认为您的缓存是
线程安全的


最好发布代码。

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

  • 这些方法是公开的吗
  • 这些方法是同步的吗
  • 只有通过这些方法才能访问地图

  • 我建议你仔细研究,掌握问题以及如何解决它们。探索这门课可以提供关于你的问题的更多信息。

    你应该使用。它提供了比synchronized doAction更好的吞吐量和比Collections.synchronizedMap()更好的线程安全性

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

    这取决于您的代码。正如其他人所说,您可以使用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);
      }
    }
    

    我想你的意思是doAction是一个同步的方法?(它不在您的代码片段中。)您是否在3个方法上有
    synchronized
    关键字:addDataIn,等等?确实正确。其他方法是私有的,不能直接同步。这意味着您的线程一次只能添加、获取或删除一个线程,我不得不说,这不是最好的解决方案。我不认为这是一个使缓存方法不同步并使入口点同步的好主意,因为如果您可以执行一个单独的操作。对不起,没有注意到synchronized关键字更具体,即使您将synchronized关键字从doAction()移开对于removeDataFromMyMap()这样的特定方法,这是不够的。由于您是在入口公共方法级别进行同步,上述操作会给您带来一些小的性能损失(微秒级),但会保证线程安全。有一次,我对ConcurrentHashMap与同步的{hashmap}的性能进行了基准测试。第70个百分位大约为15微秒-多线程访问ConcurrentHashMap时,它比您同步hashmap的方式更快。谢谢,这就是重点。我刚刚添加了一个注释-是的,这是唯一一个使用同步版本的映射的入口点,可能仍然不够。看看我的答案。
    SomeExpensiveObject value = null;
    
    synchronized (map) {
      value = map.get(key);
      if (value == null) {
         value = new SomeExpensiveObject();
         map.put(key,value);
      }
    }