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