为什么HashMap是线程不安全的,实际会如何体现?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014651560/article/details/81290533

  同步,指的是在一个时间点只能有一个线程可以修改hash表,任何线程在执行Hashtable的更新操作前都需要获取对象锁,其他线程则等待锁的释放。
  
  第一,如果多个线程同时使用put方法添加元素。

  假设正好存在两个put的key发生了碰撞(hash值一样),那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终就会发生其中一个线程的put的数据被覆盖。

  第二,如果多个线程同时检测到元素个数超过数组大小*loadFactor。

  这样会发生多个线程同时对hash数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失。且会引起死循环的错误。

如何实现HashMap的同步?

答:

  第一种方法:

   直接使用Hashtable,但是当一个线程访问HashTable的同步方法时,其他线程如果也要访问同步方法,会被阻塞住。举个例子,当一个线程使用put方法时,另一个线程不但不可以使用put方法,连get方法都不可以,效率很低,现在基本不会选择它了。

  第二种方法: HashMap可以通过下面的语句进行同步,

    Collections.synchronizeMap(hashMap);

  HashMap可以通过Map m = Collections.synchronizedMap(new HashMap())来达到同步的效果。(从源码中看出 synchronizedMap()方法返回一个SynchronizedMap类的对象,而在SynchronizedMap类中使用了synchronized来保证对Map的操作是线程安全的,故效率其实也不高。)

  具体而言,该方法返回一个同步的Map,该Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。

  第三种方法:

  直接使用JDK 5 之后的 ConcurrentHashMap,如果使用Java 5或以上的话,请使用ConcurrentHashMap。

  Collections.synchronizeMap(hashMap); 又是如何保证了HashMap线程安全?

展开阅读全文

没有更多推荐了,返回首页