博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
大杂烩 -- HashMap、HashTable、ConCurrentHashMap 联系与区别
阅读量:6297 次
发布时间:2019-06-22

本文共 2488 字,大约阅读时间需要 8 分钟。

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

1. Hashtable 和 HashMap

  ⑴ 区别,这两个类主要有以下几方面的不同:

    ⊙ Hashtable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类。

    ⊙ 在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。 因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。而在Hashtable中,无论是key还是value都不能为null 。

    ⊙ 这两个类最大的不同在于:

    (1)Hashtable是线程安全的,它的方法是同步了的,可以直接用在多线程环境中。

    (2)而HashMap则不是线程安全的。在多线程环境中,需要手动实现同步机制。

 

因此,在Collections类中提供了一个方法返回一个同步版本的HashMap用于多线程的环境:

public static 
Map
synchronizedMap(Map
m) { return new SynchronizedMap<>(m); }

该方法返回的是一个SynchronizedMap 的实例。

SynchronizedMap类是定义在Collections中的一个静态内部类。
它实现了Map接口,并对其中的每一个方法实现,通过synchronized 关键字进行了同步控制。

2. 潜在的线程安全问题

  上面提到Collections为HashMap提供了一个并发版本SynchronizedMap。这个版本中的方法都进行了同步,但是这并不等于这个类就一定是线程安全的。在某些时候会出现一些意想不到的结果。
  如下面这段代码:

// shm是SynchronizedMap的一个实例   if(shm.containsKey('key')){           shm.remove(key);   }

  这段代码用于从map中删除一个元素之前判断是否存在这个元素。 这里的containsKey和reomve方法都是同步的,但是整段代码却不是。

  考虑这么一个使用场景:线程A执行了containsKey方法返回true,准备执行remove操作;这时另一个线程B开始执行,同样执行了containsKey方法返回true,并接着执行了remove操作;然后线程A接着执行remove操作时发现此时已经没有这个元素了。要保证这段代码按我们的意愿工作,一个办法就是对这段代码进行同步控制,但是这么做付出的代价太大。

  在进行迭代时这个问题更改明显。

  Map集合共提供了三种方式来分别返回键、值、键值对的集合:

Set
keySet();
Collection
values();  
Set
> entrySet();

  在这三个方法的基础上,我们一般通过如下方式访问Map的元素:

Iterator keys = map.keySet().iterator();     while(keys.hasNext()){           map.get(keys.next());   }

  在这里,有一个地方需要注意的是:得到的keySet和迭代器都是Map中元素的一个“视图”,而不是“副本” 。

  问题也就出现在这里,当一个线程正在迭代Map中的元素时,另一个线程可能正在修改其中的元素。此时,在迭代元素时就可能会抛出 ConcurrentModificationException异常。

  为了解决这个问题通常有两种方法:

    (1)一是直接返回元素的副本,而不是视图。这个可以通过集合类的 toArray() 方法实现,但是创建副本的方式效率比之前有所降低,特别是在元素很多的情况下;

    (2)另一种方法就是在迭代的时候锁住整个集合,这样的话效率就更低了。

 

3. 更好的选择:ConcurrentHashMap

  java5中新增了ConcurrentMap接口和它的一个实现类ConcurrentHashMap。

  ConcurrentHashMap提供了和Hashtable以及SynchronizedMap中所不同的锁机制。

  Hashtable中采用的锁机制是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;

  ConcurrentHashMap中则是一次锁住一个桶。ConcurrentHashMap默认将hash表分为16个桶,诸如get,put,remove等常用操作只锁当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。

  上面说到的16个线程指的是写线程,而读操作大部分时候都不需要用到锁。只有在size等操作时才需要锁住整个hash表。

  在迭代方面,ConcurrentHashMap使用了一种不同的迭代方式。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是  在改变时new新的数据从而不影响原有的数据 。iterator完成后再将头指针替换为新的数据 。这样iterator线程可以使用原来老的数据。而写线程也可以并发的完成改变。

 

 

啦啦啦

转载地址:http://dplta.baihongyu.com/

你可能感兴趣的文章
sqoop数据迁移(基于Hadoop和关系数据库服务器之间传送数据)
查看>>
腾讯云下安装 nodejs + 实现 Nginx 反向代理
查看>>
Javascript 中的 Array 操作
查看>>
java中包容易出现的错误及权限问题
查看>>
AngularJS之初级Route【一】(六)
查看>>
服务器硬件问题整理的一点总结
查看>>
SAP S/4HANA Cloud: Revolutionizing the Next Generation of Cloud ERP
查看>>
Mellanox公司计划利用系统芯片提升存储产品速度
查看>>
白帽子守护网络安全,高薪酬成大学生就业首选!
查看>>
ARM想将芯片装进人类大脑 降低能耗是一大挑战
查看>>
Oracle数据库的备份方法
查看>>
Selenium 自动登录考勤系统
查看>>
关于如何以编程的方式执行TestNG
查看>>
智能照明造福千家万户 家居智能不再是梦
查看>>
物联网如何跳出“看起来很美”?
查看>>
浅谈MySQL 数据库性能优化
查看>>
《UNIX/Linux 系统管理技术手册(第四版)》——1.10 其他的权威文档
查看>>
灵动空间 创享生活
查看>>
《UNIX网络编程 卷1:套接字联网API(第3版)》——8.6 UDP回射客户程序:dg_cli函数...
查看>>
不要将时间浪费到编写完美代码上
查看>>