一、单线程环境下

底层:hash表结构 (数组 + 链表)

使用无参构造创建对象时 会默认长度11的数组 加载因子0.75

Hashtable<Object, Object> hashtable = new Hashtable<>();

添加第一个元素

hashtable.put("键","值");

根据键的哈希值计算出应存入的索引 例: 5;然后判断 5索引上是否为 null 如果为null 直接存入元素

添加第二个元素

根据键的哈希值计算出应存入的索引 例: 8;然后判断 8索引上是否为 null 如果为null 直接存入元素

添加第三个元素

根据键的哈希值计算出应存入的索引 例: 5


然后判断 5索引上是否为 null


此时 5 索引上 已经有了一个元素 不为null ,则会调用equals方法比较键的属性值


如果一样,则覆盖,如果不一样,则存入数组,头插的形式,老元素挂在新元素下面 形成链表结构

二、多线程环境下

采用悲观锁的方式

添加元素

多个线程添加元素时 ,线程一进入后 synchronized锁住整个数组 其他线程 等待锁释放 其他操作不变

三、JDK1.8 hashtable的put方法的底层源码

在 JDK 1.8 中,Hashtable 的 put 方法是线程安全的哈希表操作核心方法之一,其源码设计体现了同步机制、哈希冲突解决和动态扩容等关键逻辑。以下是详细的源码解析和实现原理:

1、put 方法源码

关键步骤解析

a、线程安全保证

  • put 方法被 synchronized 修饰,同一时间仅允许一个线程操作,确保线程安全

  • 缺点:在高并发场景下,同步粒度较粗,可能导致性能瓶颈(相比之下,ConcurrentHashMap 使用分段锁优化)

b、空值检查

  • 强制约束:Hashtable 不允许 key 或 value 为 null,直接抛出 NullPointerException

  • 对比:HashMap 允许 null 键和值,但需特殊处理(如 hashCode 为 0)

c、哈希值计算

  • 通过 key.hashCode() 获取哈希值

  • 哈希修正:hash & 0x7FFFFFFF 将哈希值转为正数(索引必须非负)

d、索引定位

  • 通过 (hash % tab.length) 计算索引(tab.length 是哈希表数组长度)

  • 问题:取模运算可能效率较低(HashMap 使用位运算优化)

e、链表遍历

  • 在计算出的索引位置遍历链表,检查是否存在相同键:

    • 若存在,直接替换旧值并返回旧值

    • 若不存在,调用 addEntry 插入新节点

2、插入新节点(addEntry)

  • 扩容条件:当元素数量 count 超过阈值 threshold(默认 capacity * loadFactor)

  • 头插法:新节点插入链表头部(JDK 1.8 的 HashMap 改为尾插法避免循环链表问题)

3、扩容机制(rehash)

  • 新容量:newCapacity = 2 * oldCapacity + 1(非严格的 2 倍扩容)

  • 重新哈希:所有节点需重新计算索引,并迁移到新数组

四、put方法的整个处理流程分析

put方法的整个处理流程是:计算key的hash值,根据hash值获得key在table数组中的索引位置,然后迭代该key处的Entry链表,若该链表中存在一个这个的key对象,那么就直接替换其value值即可,

否则在将改key-value节点插入该index索引位置处。如下:假设我们现在Hashtable的容量为5,已经存在了(5,5),(13,13),(16,16),(17,17),(21,21)这 5 个键值对,目前他们在Hashtable中的位置如下:

现在,我们插入一个新的键值对,put(16,22),假设key=16的索引为1.但现在索引1的位置有两个Entry了,所以程序会对链表进行迭代。迭代的过程中,发现其中有一个Entry的key和我们要插入的键值对的key相同,

所以现在会做的工作就是将newValue=22替换oldValue=16,然后返回oldValue=16.

然后我们现在再插入一个,put(33,33),key=33的索引为3,并且在链表中也不存在key=33的Entry,所以将该节点头插入链表的第一个位置。

五、总结

  • 设计目标:Hashtable 是早期线程安全哈希表实现,通过方法级同步保证安全

  • 缺点:

    • 锁粒度粗,并发性能差

    • 不支持 null 键值

    • 哈希冲突处理简单(仅链表,无红黑树优化)

  • 适用场景:低并发环境或需要兼容旧代码时(现代开发更推荐 ConcurrentHashMap)

hashtable底层的更多相关文章

  1. java面试题之HashMap和HashTable底层实现的区别

    HashMap和HashTable的区别: 相同点:都是以key和value的形式存储: 不同点: HashMap是不安全的:HashTable线程安全的(使用了synchronized关键字来保证线 ...

  2. java-vector hashtable过时?

    vector hashtable过时? 在用JAVA集合时,IDE提示 vector 以及hashtable被arraylist ,hashmap替代,而前者又是线程同步的,不知道为什么?是效率差了的 ...

  3. Java中常见数据结构:list与map -底层如何实现

    1:集合 2 Collection(单列集合) 3 List(有序,可重复) 4 ArrayList 5 底层数据结构是数组,查询快,增删慢 6 线程不安全,效率高 7 Vector 8 底层数据结构 ...

  4. HashMap、Hashtable、ConcurrentHashMap的原理与区别

    同步首发:http://www.yuanrengu.com/index.php/2017-01-17.html 如果你去面试,面试官不问你这个问题,你来找我^_^ 下面直接来干货,先说这三个Map的区 ...

  5. 集合各个实现类的底层实现原理 ----- 原文地址:https://blog.csdn.net/qq_25868207/article/details/55259978

    ArrayList实现原理要点概括 参考文献: http://zhangshixi.iteye.com/blog/674856l https://www.cnblogs.com/leesf456/p/ ...

  6. HashMap、Hashtable、ConcurrentHashMap的原理与区别(简述)

    HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相 ...

  7. hashMap,hashTable,concurrentHashMap区别

    HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相 ...

  8. 面试必备:HashMap、Hashtable、ConcurrentHashMap的原理与区别

    同步首发:http://www.yuanrengu.com/index.php/2017-01-17.html 如果你去面试,面试官不问你这个问题,你来找我^_^ 下面直接来干货,先说这三个Map的区 ...

  9. CurrentHashMap、HashMap、HashTable的区别

    HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相 ...

  10. HashMap,HashTable,concurrentHashMap,LinkedHashMap 区别

    HashMap 不是线程安全的 HashTable,concurrentHashMap 是线程安全 HashTable 底层是所有方法都加有锁(synchronized) 所以操作起来效率会低 con ...

随机推荐

  1. 多方安全计算(6):MPC中场梳理

    学习&转载文章:多方安全计算(6):MPC中场梳理 前言 诚为读者所知,数据出域的限制约束与数据流通的普遍需求共同催生了数据安全计算的需求,近一两年业界又统将能够做到多方数据可用不可见的技术归 ...

  2. Vanity Intermediate 统配符提权

    nmap扫描 ┌──(root㉿kali)-[~] └─# nmap -p- -A 192.168.167.234 Starting Nmap 7.94SVN ( https://nmap.org ) ...

  3. UTS Open '21 P7 - April Fools

    传送门 前言 本题是笔者keysky与同学yangbaich讨论+推式子一整个晚上以及讨论前ybc的一整个下午做出来的,综合起来是 \(34\) 个转移方程,对于整道题来说,贡献大抵为我 \(2\) ...

  4. Janus Pro:DeepSeek 开源革新,多模态 AI 的未来

    Janus Pro 是 DeepSeek 开发的一个开源多模态人工智能框架,它通过集成视觉和语言处理能力,提供了高性能的多模态任务处理能力. 在线体验: https://deepseek-janusp ...

  5. CF1326G 题解

    题意: 蛛网树是一颗平面树,满足点是该树的凸包的顶点上等价于其是叶子. 给定一个平面树,求有多少种对点集的划分,使得每个划分出来的集合都是蛛网树. Solution 考虑树形 dp.设 \(f_u\) ...

  6. EasyExcel 通过模板填充数据

    EasyExcel 通过模板填充数据两种方式:1.直接通过模板填充.2.通过IO流填充. 模板示例 注意:单个字段填充只写字段名即可,数据集填充需要在字段前加 . {title} 姓名 昵称 手机号 ...

  7. 如何通过 Python 实现一个消息队列,为在线客服系统与海外运营的APP对接

    我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统.陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户. 而我收到的用户需求也越来越多,产品化的 ...

  8. keil优化等级说明 keil code optimization

    其中 0级(Constan folding)的优化包括: a.常数折叠:只要有可能,编译器就执行将表达式化为常数数字的计算,其中包括运行地址的计算. b. 简单访问优化:对8051系统的内部数据和位地 ...

  9. 洛谷P11250 [GESP202409 八级] 手套配对 题解

    题目传送门. 非常简单的组合数学题. 首先从 \(n\) 对手套中恰好选出 \(k\) 对手套的方案数为 \(C_n^k\),然后由于我们要取出 \(m\) 只手套,那么取了 \(k\) 对手套后还要 ...

  10. UE5 C++ 程序进程退出

    // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include ...