Java源码详解三:Hashtable源码分析--openjdk java 11源码
文章目录
- 注释
- 哈希算法与映射
- 线程安全的实现方法
- 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.key
和value
不能为null
。
2.key
的类必须实现hashCode
和equals
方法。注释是说must
,这点存疑。
3.有2个参数影响Hashtable
实例的性能,分别是initial capacity
和load factor
。capacity
就是Hashtable
有多少个buckets
,桶。load factor
是Hashtable
有多满的时候会进行自动扩容。more的load factor
为0.75
,较高的值会减少空间开销,但会增加查找的时间成本。
4.Hashtable
处理哈希冲突的方法是在一个桶里放多个实例。
5.iterator
迭代器支持fail-fast
,也就是说在迭代器创建后,如果Hashtable
的结构发生了变化,迭代器会抛出异常ConcurrentModificationException
。迭代器不会冒风险继续迭代。fail-fast
并不能做出完全的保证,用户不应该完全依赖该异常。但keys
和elements
方法并不是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
不同了,HashMap
的capacity
必须要是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源码相关推荐
- OkHttp3源码详解(三) 拦截器-RetryAndFollowUpInterceptor
最大恢复追逐次数: private static final int MAX_FOLLOW_UPS = 20; 处理的业务: 实例化StreamAllocation,初始化一个Socket连接对象,获 ...
- Rocksdb Compaction 源码详解(一):SST文件详细格式源码解析
文章目录 前言 comapction流程概述 SST 文件细节 Footer meta index block filter meta block index meta block Compressi ...
- Java面试题详解三:比较器
一,Comparable和Comparator 1.Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较. Comparable接口中只 ...
- java多线程学习-java.util.concurrent详解
http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...
- Rocksdb Compaction源码详解(二):Compaction 完整实现过程 概览
文章目录 1. 摘要 2. Compaction 概述 3. 实现 3.1 Prepare keys 过程 3.1.1 compaction触发的条件 3.1.2 compaction 的文件筛选过程 ...
- 4.6 W 字总结!Java 11—Java 17特性详解
作者 | 民工哥技术之路 来源 | https://mp.weixin.qq.com/s/SVleHYFQeePNT7q67UoL4Q Java 11 特性详解 基于嵌套的访问控制 与 Java 语言 ...
- PackageManagerService启动详解(三)之开始初始化阶段流程分析
PKMS启动详解(三)之BOOT_PROGRESS_PMS_START阶段流程分析 Android PackageManagerService系列博客目录: PKMS启动详解系列博客概要 PKMS ...
- java异常体系结构详解
java异常体系结构详解 参考文章: (1)java异常体系结构详解 (2)https://www.cnblogs.com/hainange/p/6334042.html 备忘一下.
- java异常处理机制详解
java异常处理机制详解 参考文章: (1)java异常处理机制详解 (2)https://www.cnblogs.com/vaejava/articles/6668809.html 备忘一下.
最新文章
- matlab中sinks,MATLAB Simulink模块库详解(二)Sinks篇
- Java并发编程,无锁CAS与Unsafe类及其并发包Atomic
- java要从数据查出五百多万条数据_100w条数据 | 插入Mysql你要用多长时间?
- 【知识图谱】知识表示与知识建模
- 我今天对JavaFX的了解
- 数据结构排序法之堆排序he归并排序
- spring boot jwt_springboot整合JWT
- IBM x3650 光盘安装linux,IBM X3650 M3服务器安装SUSE LINUX 10实战
- 致命错误: 在类路径或引导类路径中找不到程序包 java.lang_如何提升店铺动态评分 需要提升可以找我...
- JavaWEB开发的国际化
- VB.Net程序设计:分页控件
- 【计算机网络】信源编码——香农三大定理
- 一个开源的会议管理系统,适合初学者练手(老司机请忽略)
- c语言 字母常量,C语言常量的类型
- python爬取京东一款手机的评论
- TWaver HTML5 高性能拓扑
- 执行 taro init myApp 报错 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\taro.ps1
- 【Python】程序员也可以很会撩:如何一键生成漂亮的生日快乐词云
- 51单片机,点亮LED灯和闪烁
- maxcompute-入门-环境安装
热门文章
- 实战药物分子筛选之一_初探
- 分片哈希piecewise hashing
- mysql+select+unlock_MySQL的locktables和unlocktables的用法(转载)
- 做工程师不懂这七点,难怪你总是混不好
- Microbiome:浙大马忠华团队-生防细菌抑制病原真菌新机制
- NAR:宏基因组网络分析工具MetagenoNets
- 这个能快速发表Cell,Nature,Molecular cell的分析技术你要错过吗?
- ggtree美颜进化树-宏基因组扩增子
- Comment:研究微生物,只靠多组学根本不够
- pandas使用resample函数计算每个月的统计均值、使用matplotlib可视化特定年份的按月均值