HashTable 与 HashMap 的区别
一、 HashTable 与 HashMap
1.1 HashTable 继承于 Dictionary 类
这里 table 里创建的是 Entry的接口
类中就是键值对和根据 hashcode 计算的 hash 值, 用于让 Entry 在 table 中分布得更加均匀, 减少 hash 冲突
1.2 两者区别
hashmap 大致等于 hashtable, 除了 hashtable 是线程安全的, 并且允许 null value 和 null key
两者都是Map接口的实现, 但是 hashmap 是继承与 AbstractMap 类
二、fail-fast 与 fail-safe
2.1 fail-fast 的解释
Dash查看文档 hashtable 文档中有一段话讲到
由这个类的所有“集合视图方法”返回的集合的迭代器方法返回的迭代器是fail fast的, 但是用 iterator 本身的方法则不会.
原因是 iterator 遍历集合的时候, 如果集合结构发生了变化(如: 删除一个 key - value) 则会抛出 ConcurrentModificationException
, 但是修改则不会.
原因是其中有个变量 modCount
用以统计HashMap 结构改变的次数,
如果在遍历过程中有其他线程改变了 HashMap 的结构, 则造成 modCount 与 expectedModCount 不相等则抛出错误.
这里异常的抛出条件是检测到 modCount!= expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。
2.2 安全失败(fail-safe)
采用安全失败机制的集合容器, 在遍历时不是直接在集合内容上访问的, 而是先复制原有集合内容, 在拷贝的集合上进行遍历.
原理: 由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception.
缺点: 基于拷贝内容的优点是避免了 Concurrent Modification Exception, 但同样地, 迭代器并不能访问到修改后的内容,即: 迭代器遍历的是开始遍历那一刻拿到的集合拷贝, 在遍历期间原集合发生的修改迭代器是不知道的.
场景: java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。