1. 概述

上次讨论了HashMap的结构,原理和实现,本文来对Map家族的另外一个常用集合HashTable进行介绍。HashTable和HashMap两种集合非常相似,经常被各种面试官问到两者的区别。

对于两者的区别,主要有以下几点:

  1. HashMap是非同步的,没有对读写等操作进行锁保护,所以是线程不安全的,在多线程场景下会出现数据不一致的问题。而HashTable是同步的,所有的读写等操作都进行了锁(synchronized)保护,在多线程环境下没有安全问题。但是锁保护也是有代价的,会对读写的效率产生较大影响。
  2. HashMap结构中,是允许保存null的,Entry.keyEntry.value均可以为null。但是HashTable中是不允许保存null的。
  3. HashMap的迭代器(Iterator)是fail-fast迭代器,但是Hashtable的迭代器(enumerator)不是fail-fast的。如果有其它线程对HashMap进行的添加/删除元素,将会抛出ConcurrentModificationException,但迭代器本身的remove方法移除元素则不会抛出异常。这条同样也是Enumeration和Iterator的区别。

    2. 原理

    HashTable类中,保存实际数据的,依然是Entry对象。其数据结构与HashMap是相同的。

    HashTable类继承自Dictionary类,实现了三个接口,分别是MapCloneablejava.io.Serializable,如下图所示。

HashTable中的主要方法,如putgetremoverehash等,与HashMap中的功能相同,这里不作赘述,可以参考另外一篇文章HashMap原理和底层实现

3. 源码分析

HashTable的主要方法的源码实现逻辑,与HashMap中非常相似,有一点重大区别就是所有的操作都是通过synchronized锁保护的。只有获得了对应的锁,才能进行后续的读写等操作。

1. put方法

put方法的主要逻辑如下:

  1. 先获取synchronized锁。
  2. put方法不允许null值,如果发现是null,则直接抛出异常。
  3. 计算key的哈希值和index
  4. 遍历对应位置的链表,如果发现已经存在相同的hash和key,则更新value,并返回旧值。
  5. 如果不存在相同的key的Entry节点,则调用addEntry方法增加节点。
  6. addEntry方法中,如果需要则进行扩容,之后添加新节点到链表头部。
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
} // Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
} addEntry(hash, key, value, index);
return null;
}
    private void addEntry(int hash, K key, V value, int index) {
modCount++; Entry<?,?> tab[] = table;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash(); tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
} // Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}

2. get方法

get方法的主要逻辑如下

  1. 先获取synchronized锁。
  2. 计算key的哈希值和index。
  3. 在对应位置的链表中寻找具有相同hash和key的节点,返回节点的value。
  4. 如果遍历结束都没有找到节点,则返回null
public synchronized V get(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return (V)e.value;
}
}
return null;
}

3.rehash扩容方法

rehash扩容方法主要逻辑如下:

  1. 数组长度增加一倍(如果超过上限,则设置成上限值)。
  2. 更新哈希表的扩容门限值。
  3. 遍历旧表中的节点,计算在新表中的index,插入到对应位置链表的头部。
    protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table; // overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap; for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}

4.remove方法

remove方法主要逻辑如下:

  1. 先获取synchronized锁。
  2. 计算key的哈希值和index。
  3. 遍历对应位置的链表,寻找待删除节点,如果存在,用e表示待删除节点,pre表示前驱节点。如果不存在,返回null
  4. 更新前驱节点的next,指向e的next。返回待删除节点的value值。

4. 总结

HashTable相对于HashMap的最大特点就是线程安全,所有的操作都是被synchronized锁保护的

作者:道可
链接:https://www.imooc.com/article/details/id/23015
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

HashTable原理和底层实现的更多相关文章

  1. Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)

    Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 分类: Android开发 Androi ...

  2. HashMap与HashTable原理及数据结构

    HashMap与HashTable原理及数据结构 hash表结构个人理解 hash表结构,以计算出的hashcode或者在hashcode基础上加工一个hash值,再通过一个散列算法 获取到对应的数组 ...

  3. java8 HashTable 原理

    HashTable原理 Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现.Hashtable中的方法是同步的,而HashMap方法(在 ...

  4. HashMap的实现原理和底层数据结构

    看了下Java里面有HashMap.Hashtable.HashSet三种hash集合的实现源码,这里总结下,理解错误的地方还望指正 HashMap和Hashtable的区别 HashSet和Hash ...

  5. Git 内部原理 - (1)底层命令和高层命令 (2Git 对象

    文章摘选自git官网,这里复制下来表示我已阅读并学习过一次这些内容: 无论是从之前的章节直接跳到本章,还是读完了其余章节一直到这——你都将在本章见识到 Git 的内部工作原理和实现方式. 我们发现学习 ...

  6. Java集合详解(五):Hashtable原理解析

    概述 本文是基于jdk8_271版本进行分析的. Hashtable与HashMap一样,是一个存储key-value的双列集合.底层是基于数组+链表实现的,没有红黑树结构.Hashtable默认初始 ...

  7. <TCP/IP原理> (三) 底层网络技术

    传输介质 局域网(LAN) 交换(Switching) 广域网(WAN) 连接设备 第三章 底层网络技术 引言 1)Interne不是一种新的网络 建立在底层网络上的网际网 底层网络——“物理网”,网 ...

  8. HashTable原理与源码分析

    本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正! HashTable内部存储结构 HashTable内部存储结构为数组+单向链 ...

  9. 五.HashTable原理及实现学习总结

    有两个类都提供了一个多种用途的hashTable机制,他们都可以将可以key和value结合起来构成键值对通过put(key,value)方法保存起来,然后通过get(key)方法获取相对应的valu ...

随机推荐

  1. Node性能如何进行监控以及优化?

    一. 是什么 Node作为一门服务端语言,性能方面尤为重要,其衡量指标一般有如下: CPU 内存 I/O 网络 CPU 主要分成了两部分: CPU负载:在某个时间段内,占用以及等待CPU的进程总数 C ...

  2. matlab——插值与拟合

    @ 目录 前言 一.拟合 1.定义 2.三种判别准则 3.最小二乘法 (1)一般形式 (2)常用函数 (3)matlab实现 二.插值 1.定义 2.方法 (1)分段线性插值 (2)拉格朗日插值多项式 ...

  3. Token验证详解

    为什么使用Token验证: 在Web领域基于Token的身份验证随处可见.在大多数使用Web API的互联网公司中,tokens 是多用户下处理认证的最佳方式. 以下几点特性会让你在程序中使用基于To ...

  4. keeplived+mycat+mysql高可用读写分离水平分表(谁看谁都会)

    一:环境准备: 应用 主机 mysql-master 192.168.205.184 mysql-slave 192.168.205.185 mycat-01,keeplived,jdk 192.16 ...

  5. 基于SSM小区物业管理系统

    随着计算机的不断发展和广泛应用,人们的工作效率得到不断的提高.互联网的发展,更是缩短了人们之间的距离.如何充分利用互联网,这是大家共同关心的问题.本文主要介绍了关于小区管理系统的实现方法,设计规划了小 ...

  6. 单细胞分析实录(18): 基于CellPhoneDB的细胞通讯分析及可视化 (上篇)

    细胞通讯分析可以给我们一些细胞类群之间相互调控/交流的信息,这种细胞之间的调控主要是通过受配体结合,传递信号来实现的.不同的分化.疾病过程,可能存在特异的细胞通讯关系,因此阐明这些通讯关系至关重要. ...

  7. ArcGis API JS 4.X本地化部署与地图的基础使用

    准备工作 首先下载ArcGIS API for JavaScript4.x,这里下载的是4.19. 官方下载地址:https://developers.arcgis.com/downloads/ ar ...

  8. jvm源码解读--12 invokspecial指令的解读

    先看代码 package com.zyt.jvmbook; public class Girl extends Person{ public Girl() { int a; } @Override p ...

  9. js 调用json

    url = "/plus/API/"; try { // 此处是可能产生例外的语句 } catch(error) { // 此处是负责例外处理的语句 } finally { // ...

  10. YOLO-v4 口罩识别

    YOLO-v4 口罩识别 一.YOLO-v4概念 如果想要了解和认识yolo-v4的基本概念,首先要提的就是它的基础版本yolo-v1,对于yolo来说,最经典的算是yolo-v3.如果想要了解它的由 ...