文章目录

  • 注释
  • 哈希算法与映射
  • 线程安全的实现方法
  • put 操作
  • get操作

本系列是Java详解,专栏地址:Java源码分析


Hashtable官方文档:Hashtable (Java Platform SE 8 )
Hashtable.java源码共1522行,下载地址见我的文章:Java源码下载和阅读(JDK1.8/Java 11)

文件地址:openjdk-jdk11u-jdk-11.0.6-3/src/java.base/share/classes/java/util


想看Hashtable源码的一个重要的原因是:HashMap不是线程安全的,Hashtable是线程安全的
我很好奇Hashtable如何实现线程安全。


注释

看源码的第一步是看代码开始前的注释,注释里提到几个点:

1.keyvalue不能为null
2.key的类必须实现hashCodeequals方法。注释是说must,这点存疑。
3.有2个参数影响Hashtable实例的性能,分别是initial capacityload factorcapacity就是Hashtable有多少个buckets,桶。load factorHashtable有多满的时候会进行自动扩容。more的load factor0.75,较高的值会减少空间开销,但会增加查找的时间成本。
4.Hashtable处理哈希冲突的方法是在一个桶里放多个实例。
5.iterator迭代器支持fail-fast,也就是说在迭代器创建后,如果Hashtable的结构发生了变化,迭代器会抛出异常ConcurrentModificationException。迭代器不会冒风险继续迭代。fail-fast并不能做出完全的保证,用户不应该完全依赖该异常。但keyselements方法并不是fail-fast的。
6.Hashtable是线程安全的,如果不需要线程安全,推荐使用HashMap。如果需要线程安全,推荐ConcurrentHashMap。总之不推荐Hashtable


类的继承如下:

public class Hashtable<K,V>extends Dictionary<K,V>implements Map<K,V>, Cloneable, java.io.Serializable

使用默认的构造函数:

public Hashtable() {this(11, 0.75f);}

默认的初始initialCapacity为11,load factor为0.75。
这里就和HashMap不同了,HashMapcapacity必须要是2的幂次。
capacity的要求不同是因为采用了不同的哈希映射的方法。
HashTable默认的初始大小为11,之后每次扩充为原来的2n+1。
HashTable会尽量使用素数、奇数。当哈希表的大小为素数时,简单的取模哈希的结果会更加均匀


哈希算法与映射

Hashtable做法如下:

int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;// & 0x7FFFFFFF是为了让结果为正数

HashMap做法如下:

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);

Hashtable的代码是多年前的,HashMap的做法更优,主要是因为按位与比除法快。当然缺点就是哈希函数必须设计的很好,因此对hashCode的结果进行了位移操作。


线程安全的实现方法

Hashtable实现线程安全的方法是把大部分public的方法前都加上关键字synchronized
真是简单粗暴的做法。

put 操作

put操作是synchronized的,具体的思路跟HashMap基本一样。
1.key或value为null抛出异常
2.算出哈希,映射到数组下标
3.如果存在一样的key,直接替换value
4.不存在的话,在最后加上新的节点,有人把这个方法叫做"拉链法"。
5.扩容的话,容量*2+1。

    public synchronized V put(K key, V value) {// Make sure the value is not nullif (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) {Entry<?,?> tab[] = table;if (count >= threshold) {// Rehash the table if the threshold is exceededrehash();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++;modCount++;}

get操作

代码很简单,不分析了:

    @SuppressWarnings("unchecked")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;}

参考:

  • java - Why is the initialCapacity of Hashtable 11 while the DEFAULT_INITIAL_CAPACITY in HashMap is 16 and requires a power of 2? - Stack Overflow
  • HashMap和HashTable到底哪不同?
  • 带你深入浅出的分析 HashTable 源码

Java源码详解三:Hashtable源码分析--openjdk java 11源码相关推荐

  1. OkHttp3源码详解(三) 拦截器-RetryAndFollowUpInterceptor

    最大恢复追逐次数: private static final int MAX_FOLLOW_UPS = 20; 处理的业务: 实例化StreamAllocation,初始化一个Socket连接对象,获 ...

  2. Rocksdb Compaction 源码详解(一):SST文件详细格式源码解析

    文章目录 前言 comapction流程概述 SST 文件细节 Footer meta index block filter meta block index meta block Compressi ...

  3. Java面试题详解三:比较器

    一,Comparable和Comparator 1.Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较. Comparable接口中只 ...

  4. java多线程学习-java.util.concurrent详解

    http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...

  5. Rocksdb Compaction源码详解(二):Compaction 完整实现过程 概览

    文章目录 1. 摘要 2. Compaction 概述 3. 实现 3.1 Prepare keys 过程 3.1.1 compaction触发的条件 3.1.2 compaction 的文件筛选过程 ...

  6. 4.6 W 字总结!Java 11—Java 17特性详解

    作者 | 民工哥技术之路 来源 | https://mp.weixin.qq.com/s/SVleHYFQeePNT7q67UoL4Q Java 11 特性详解 基于嵌套的访问控制 与 Java 语言 ...

  7. PackageManagerService启动详解(三)之开始初始化阶段流程分析

      PKMS启动详解(三)之BOOT_PROGRESS_PMS_START阶段流程分析 Android PackageManagerService系列博客目录: PKMS启动详解系列博客概要 PKMS ...

  8. java异常体系结构详解

    java异常体系结构详解 参考文章: (1)java异常体系结构详解 (2)https://www.cnblogs.com/hainange/p/6334042.html 备忘一下.

  9. java异常处理机制详解

    java异常处理机制详解 参考文章: (1)java异常处理机制详解 (2)https://www.cnblogs.com/vaejava/articles/6668809.html 备忘一下.

最新文章

  1. matlab中sinks,MATLAB Simulink模块库详解(二)Sinks篇
  2. Java并发编程,无锁CAS与Unsafe类及其并发包Atomic
  3. java要从数据查出五百多万条数据_100w条数据 | 插入Mysql你要用多长时间?
  4. 【知识图谱】知识表示与知识建模
  5. 我今天对JavaFX的了解
  6. 数据结构排序法之堆排序he归并排序
  7. spring boot jwt_springboot整合JWT
  8. IBM x3650 光盘安装linux,IBM X3650 M3服务器安装SUSE LINUX 10实战
  9. 致命错误: 在类路径或引导类路径中找不到程序包 java.lang_如何提升店铺动态评分 需要提升可以找我...
  10. JavaWEB开发的国际化
  11. VB.Net程序设计:分页控件
  12. 【计算机网络】信源编码——香农三大定理
  13. 一个开源的会议管理系统,适合初学者练手(老司机请忽略)
  14. c语言 字母常量,C语言常量的类型
  15. python爬取京东一款手机的评论
  16. TWaver HTML5 高性能拓扑
  17. 执行 taro init myApp 报错 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\taro.ps1
  18. 【Python】程序员也可以很会撩:如何一键生成漂亮的生日快乐词云
  19. 51单片机,点亮LED灯和闪烁
  20. maxcompute-入门-环境安装

热门文章

  1. 实战药物分子筛选之一_初探
  2. 分片哈希piecewise hashing
  3. mysql+select+unlock_MySQL的locktables和unlocktables的用法(转载)
  4. 做工程师不懂这七点,难怪你总是混不好
  5. Microbiome:浙大马忠华团队-生防细菌抑制病原真菌新机制
  6. NAR:宏基因组网络分析工具MetagenoNets
  7. 这个能快速发表Cell,Nature,Molecular cell的分析技术你要错过吗?
  8. ggtree美颜进化树-宏基因组扩增子
  9. Comment:研究微生物,只靠多组学根本不够
  10. pandas使用resample函数计算每个月的统计均值、使用matplotlib可视化特定年份的按月均值