【Java】非线程安全的HashMap

总结

在以前的多线程环境中,当多个应用程序访问”java.util.HashMap”时,可能会出现无响应或HashMap的值发生更改等情况。我打算在备忘录中记录以下内容,包括可能的原因和解决方案。

原因

非常简单,并且由于没有理解”java.util.HashMap”在多个线程同时执行put或get时无法保证返回什么,或者在使用时没有进行互斥控制,因此发生了这种情况。 当调查这个现象时,我们发现这个问题从很久以前就在各种网站上有所记载。

执行HashMap.put时,似乎会重建HashMap内的数据结构。
在这个过程中,如果执行get操作,则会根据指定的键信息去搜索目标。但由于重建中,可能会无限循环搜索,并且无法预测会返回什么样的响应。
这是常被提到的同时执行put和get时发生的无限循环或数据结构破坏的事件。

img01.png

应对

对待方式会根据每个事件而有所不同。

我不知道将发生什么响应。
这是因为对HashMap进行get和put的同时访问导致的,因此需要对同时访问进行同步,当某人正在访问时,另一个人需要等待访问。
– synchronized方法
对方法进行互斥控制。

public synchronized static void putMap(String[] args){
  // ~何かしらの処理~
}

如果有人在使用这个方法,那么从其他地方访问的人将处于等待状态,直到第一个访问者的处理(在synchronized范围内)结束为止。
然而,上述示例是一个静态方法,所以即使在多线程环境下也有效。但是,对于非静态方法,它将成为实例范围,因此对于线程间的互斥控制无效,需要注意。

将HashMap更改为从jdk1.5开始可用的ConcurrentHashMap。

private static ConcurrentHashMap<String,String> map = new ConcurrentHashMap<String,String>();

HashMap是非线程安全的,但是ConcurrentHashMap是线程安全的,并且会自动进行同步操作。
不需要自己去实现synchronized,这样可以提高性能。
因此,如果存在多个线程频繁访问的情况下,最好使用ConcurrentHashMap。

由于从多个线程访问静态变量,因此根据时间的不同,HashMap的值会发生变化是自然的。如果您不希望更改自己放入的值,那么需要进行互斥控制,或者将对象复制(克隆)到线程本地变量中进行使用等相应的处理措施是必要的。

总结

在编写源代码时,即使以冷淡的态度进行,很难意识到程序将在哪种环境中运行。如果不在编写过程中意识到这一点,日后的调查等都会变得非常困难。
所以,我认为最好在编写时始终要意识到一些问题,比如是否线程安全,经常变动是否可行,以及资源应该由谁利用等。

请提供以下内容的中文本地化转述,仅需要一种选项:

参考文献

・在”せろ部屋”的谷本心
・Thread和HashMap中的无尽回廊是不是非常有趣?

广告
将在 10 秒后关闭
bannerAds