Hashtable如何保证线程安全

  • 前言
  • Hashtable中的常用变量
  • Hashtable中的常用方法
    • 构造方法
    • contains()
    • rehash()
    • addEntry()
    • put()
    • 其他方法
  • Hashtable与HashMap的区别

前言

HashMap是非同步的,没有对读写等操作进行锁保护,是线程不安全的。
Hashtable是同步的,所有的读写操作都进行了锁保护,是线程安全的。
Hashtable的底层是数组+链表实现的

Hashtable中的常用变量

private transient Entry<?,?>[] table; //底层保存节点的数组
private transient int count;  //记录表中的节点数
private int threshold;   //阈值,当表的节点数>=该阈值,会进行扩容
private float loadFactor;  //负载因子,计算阈值用的
private transient int modCount = 0;  //Hashtable在结构上被修改的次数
// 计算节点在数组的下标
int index = (hash & 0x7FFFFFFF) % tab.length;

Hashtable中的常用方法

构造方法

1.传入初始容量和负载因子

2.只传入初始容量,默认的负载因子是0.75

3.默认的初始容量是11,负载因子是0.75

contains()

用synchronized关键字保证线程安全

  public synchronized boolean containsKey(Object key) {Entry<?,?> tab[] = table; //表int hash = key.hashCode();//计算key在数组中的下标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 true;}}return false;}

rehash()

对表进行扩容的方法

 protected void rehash() {int oldCapacity = table.length;  //旧表的长度Entry<?,?>[] oldMap = table;// overflow-conscious code//新的容量=旧的容量*2+1int newCapacity = (oldCapacity << 1) + 1;//如果新的容量>Integer.MAX_VALUE-8if (newCapacity - MAX_ARRAY_SIZE > 0) {if (oldCapacity == MAX_ARRAY_SIZE)// Keep running with MAX_ARRAY_SIZE bucketsreturn;newCapacity = MAX_ARRAY_SIZE;}//建立新的数组Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];//修改次数+1modCount++;//重新计算阈值threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);table = newMap;  //将新数组赋值给table//将旧数组的值放到新数组中去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放在链表头上e.next = (Entry<K,V>)newMap[index];newMap[index] = e;}}}

addEntry()

加入节点的方法,虽然没用synchronized,但是方法是私有的

 private void addEntry(int hash, K key, V value, int index) {Entry<?,?> tab[] = table;//当插入的数量>=threshold 第一次扩容是加入第9个数的时候if (count >= threshold) {// Rehash the table if the threshold is exceededrehash();  //扩容tab = table; //此时table已经在扩容方法中变了,重新赋值hash = key.hashCode();//  计算key在数组中的位置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++;}

put()

放入数值
用synchronized保证线程安全

 public synchronized V put(K key, V value) {// Make sure the value is not null//放入的值不能是nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();//计算indexint index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];//循环链表for(; entry != null ; entry = entry.next) {//如果找到了相同的key值if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;//新值覆盖旧值,并返回旧值entry.value = value;return old;}}//调用addEntry值addEntry(hash, key, value, index);return null;}

其他方法






都是用synchronized关键字保证线程安全
Hash
Hashtable效率低下,容器越大,对容器数据操作的效率越低

Hashtable与HashMap的区别

  • HashMap是线程不安全的,Hashtable是线程安全

  • HashMap的底层实现是数组+链表+红黑树,Hashtable的底层实现是数组+链表

  • HashMap确定index:index=hash&(table.length-1;
    Hashtable确定index:index = (hash & 0x7FFFFFFF) % tab.length;
    比较:Hashtable相当于直接将hash值对数组长度取模(根0x7FFFFFFF做&是为了保证hashcode的值为正数),保证了节点在数组分配上比较均匀,但是取模操作的消耗很大,HashMap中&的操作降低消耗

  • hashMap的初始容量为16,Hashtable的初始容量为11

  • hashMap扩容时 新容量=旧容量2
    hashtable扩容时 新容量=旧容量
    2+1

Hashtable如何保证线程安全相关推荐

  1. 它又来了!C**HashMap是如何保证线程安全的?会用不就完了?

    欢迎关注方志朋的博客,回复"666"获面试宝典 阅读此篇文章,你需要有以下知识基础 Java内存模型,可见性问题 CAS HashMap底层原理 我们知道,在日常开发中使用的Has ...

  2. 对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全

    转载自 对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全 之前在公众号中问了这个问题:对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全? 三天之内收到1 ...

  3. concurrenthashmap_ConcurrentHashMap是如何保证线程安全的

    文章已同步发表于微信公众号JasonGaoH,ConcurrentHashMap是如何保证线程安全的 之前分析过HashMap的一些实现细节,关于HashMap你需要知道的一些细节, 今天我们从源码角 ...

  4. ConcurrentHashMap是如何保证线程安全的,你知道么?

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/qq_41737716/ article/details/90549847 前言 阅读此篇文章,你需要有以下知识基础 Java内 ...

  5. 多线程情况下如何保证线程安全

    一.线程安全等级 其实线程安全并不是一个"非黑即白"单项选择题.按照"线程安全"的安全程度由强到弱来排序,我们可以将java语言中各种操作共享的数据分为以下5类 ...

  6. 到底如何保证线程安全,总结得太好了。。

    一.线程安全等级 之前的博客中已有所提及"线程安全"问题,一般我们常说某某类是线程安全的,某某是非线程安全的.其实线程安全并不是一个"非黑即白"单项选择题. 按 ...

  7. 精妙绝伦的并发艺术品 — ConcurrentHashMap是如何保证线程安全的

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"书",获取 后台回复"k8s",可领取k8s资料 | 前言 阅读此 ...

  8. ConcurrentHashMap 是如何保证线程安全的,你知道么?

    点击下方"IT牧场",选择"设为星标" blog.csdn.net/qq_41737716/article/details/90549847 01.前言 02. ...

  9. 面试官:ConcurrentHashMap 是如何保证线程安全的

    点击"终码一生",关注,置顶公众号 每日技术干货,第一时间送达! 1.前言 阅读此篇文章,你需要有以下知识基础 Java内存模型,可见性问题 CAS HashMap底层原理 我们知 ...

  10. SQLite第三方框架FMDB的使用,以及使用FMDatabaseQueue保证线程安全

    2019独角兽企业重金招聘Python工程师标准>>> (1)下载地址:https://github.com/ccgus/fmdb (2)注意点 --语句可以带分号":&q ...

最新文章

  1. 安卓帧数监测软件_土壤墒情监测仪
  2. 轮滑---1、动作和杂记
  3. Sparsity稀疏编码(一)
  4. 用forif循环测量minst0-6的特征迭代次数曲线
  5. kaggle房价预测问题
  6. vs azure web_在Azure中迁移和自动化Chrome Web爬网程序的指南。
  7. 计算机程序设计基础试题与答案,2018年4月自考计算机基础与程序设计02275试题及答案.doc...
  8. 曾经辉煌无限,如今员工持续大量流失,集团目前仅剩10余人
  9. 腾讯云推出首款自研服务器星星海;苹果新款Mac Pro整套配齐超30万;Fedora 31稳定版发布|极客头条...
  10. python如何用色度表示数值大小_python入门004数字(例程界面很清晰大小也合适)
  11. 老手萌新学习composer的使用
  12. 阿里算法工程师模拟题2018/5/7
  13. 记centos7.2+上tomcat启动成功的监控脚本和nginx可配置多个域名
  14. 使用megacli命理查看硬raid信息
  15. 在IDEA中实现Python随机森林模型预测人口
  16. Linux系统交换空间详解
  17. java根据逗号拆分_Excel拆分单元格文本,一列变多列,你学会了吗?
  18. Nginx 单IP绑定多域名配置 顶级域名重定向到www域名
  19. 打包chromium浏览器
  20. layerui如何隐藏按钮?

热门文章

  1. CC2430基础——LED控制实验
  2. word中批量修改图片大小的两个方法
  3. java倍数增长计算公式,增长倍数计算公式是什么
  4. 各种路由的概念-直连路由、网关路由、主机路由、网络路由等
  5. 建筑CAD基础设计【2】
  6. postgresql用户和角色
  7. java中数字转换汉语中人民币的大写
  8. winrm java客户端_Windows 远程管理WinRM | 学步园
  9. 用Python模拟QQ界面之QQ登录界面的奥秘
  10. 【电路】PT1000/PT100温度采集电路