看了一下api,为什么HashTable的webapi 多个get方法法也用synchronized修饰?只是读啊

get(Object key)&方法用于获得指定键映射此到哈希表中的值。
以下是java.util.Hashtable.get()方法的声明。
public V get(Object key)
key--在哈希表中的键。
方法调用返回该键所映射此哈希表中的值。
NullPointerException--如果该键为null,这会被抛出。
下面的例子显示java.util.Hashtable.get()方法的使用
package com.yiibai;
import java.util.*;
public class HashTableDemo {
public static void main(String args[]) {
// create hash table
Hashtable htable1 = new Hashtable();
// put values in table
htable1.put(1, &A&);
htable1.put(2, &B&);
htable1.put(3, &C&);
htable1.put(4, &D&);
// get values at key 3
System.out.println(&Values at key 3 is:&+htable1.get(3));
现在编译和运行上面的代码示例,将产生以下结果。
Values at key 3 is:C
易百教程移动端:请扫描本页面底部(右侧)二维码并关注微信公众号,回复:"教程" 选择相关教程阅读或直接访问:http://m.yiibai.com 。
上一篇:下一篇:
加QQ群啦,易百教程官方技术学习群
注意:建议每个人选自己的技术方向加群,同一个QQ最多限加3个群。
Java技术群:
(人数:2000,等级:LV5,免费:否)
MySQL/SQL群:
(人数:2000,等级:LV5,免费:否)
大数据开发群:
(人数:2000,等级:LV5,免费:否)
Python技术群:
(人数:2000,等级:LV5,免费:否)
人工智能深度学习:
(人数:2000,等级:LV5,免费:否)
测试工程师(新群):
(人数:1000,等级:LV1,免费:是)
前端技术群(新群):
(人数:1000,等级:LV1,免费:是)
C/C++技术(新群):
(人数:1000,等级:LV1,免费:是)
Node.js技术(新群):
(人数:1000,等级:LV1,免费:是)
PostgreSQL数据库(新群):
(人数:1000,等级:LV1,免费:否)
Linux技术:
(人数:2000,等级:LV5,免费:否)
PHP开发者:
(人数:2000,等级:LV5,免费:是)
Oracle数据库:
(人数:2000,等级:LV5,免费:是)
C#/ASP.Net开发者:
(人数:2000,等级:LV5,免费:是)
数据分析师:
(人数:1000,等级:LV1,免费:是)R语言,Matlab语言等技术追求进步,永不止步!
从源码层理解Hashtable中的put和get
首先我们先看put方法:将指定 key 映射到此哈希表中的指定 value。注意这里键key和值value都不可为空。
put方法的整个处理流程是:计算key的hash值,根据hash值获得key在table数组中的索引位置,然后迭代该key处的Entry链表(我们暂且理解为链表),若该链表中存在一个这个的key对象,那么就直接替换其value值即可,否则在将改key-value节点插入该index索引位置处。如下:
首先我们假设一个容量为5的table,存在8、10、13、16、17、21。他们在table中位置如下:
然后我们插入一个数:put(16,22),key=16在table的索引位置为1,同时在1索引位置有两个数,程序对该“链表”进行迭代,发现存在一个key=16,这时要做的工作就是用newValue=22替换oldValue16,并将oldValue=16返回。
在put(33,33),key=33所在的索引位置为3,并且在该链表中也没有存在某个key=33的节点,所以就将该节点插入该链表的第一个位置。
在HashTabled的put方法中有两个地方需要注意:
1、HashTable的扩容操作,在put方法中,如果需要向table[]中添加Entry元素,会首先进行容量校验,如果容量已经达到了阀值,HashTable就会进行扩容处理rehash(),如下:
在这个rehash()方法中我们可以看到容量扩大两倍+1,同时需要将原来HashTable中的元素一一复制到新的HashTable中,这个过程是比较消耗时间的,同时还需要重新计算hashSeed的,毕竟容量已经变了。这里对阀值啰嗦一下:比如初始值11、加载因子默认0.75,那么这个时候阀值threshold=8,当容器中的元素达到8时,HashTable进行一次扩容操作,容量 = 11* 2 + 1 =23,而阀值threshold=23*0.75
= 17,当容器元素再一次达到阀值时,HashTable还会进行扩容操作,一次类推。
2、在计算索引位置index时,HashTable进行了一个与运算过程(hash & 0x7FFFFFFF)下面是计算key的hash值,这里hashSeed发挥了作用。
相对于put方法,get方法就会比较简单,处理过程就是计算key的hash值,判断在table数组中的索引位置,然后迭代链表,匹配直到找到相对应key的value,若没有找到返回null。
没有更多推荐了,推荐这篇日记的豆列
&&&&&&&&&&&&关于hashmap和hashtable的区别,及如何使hashmap变得线程安全?(除了synchronized)---concurrentHashmap
我们都知道hashmap是线程不安全的,而效率也比较高,他允许我们存入null键及null值;
而 hashtable 是线程安全的,其效率比较低,不允许我们存入null键和null值;
除了非同步及允许使用null值,hashmap与hashtable基本相同;
那么为什么hashtable是线程安全的呢?我们可以翻看一下:
例如:put 方法,hashtable中几乎所有的方法都是被synchronized 修饰的;以保证其安全性;
synchronized 可以修饰静态方法(锁对象为本类的字节码文件对象)、修饰普通方法(锁对象为this,即谁调用了它)、修饰某段代码(锁对象为任意对象);
再来说hashmap,它的get put 方法没有加同步,那么意味着,如果2个线程同时put了两个相同的key时,这2个key会被放到数组中的同一位置,(hashmap 中的key是
用数组来存储的),就会导致其中一个线程put的数据被覆盖;另外:hashmap并发执行put 操作时会引起死循环(其实是发生在数组扩容时,hashmap 中的node链表
形成环形数据结构)。
所以在api中给出了这样的方法保证hashmap的安全:
Map m = Collections.synchronizedMap(new HashMap(...));
当然还有另外一种方法就是:使用ConcurrentHashmap:这个类遵守与相同的功能规范,即支持的所有功能(注意:它不 允许将 null 用作键或值);
除此之外还支持多线程对map 的读操作,在执行写操作时,CHM只锁住部分的Map,同时支持16个进程进行写操作,读操作不受限制;
原因在于ConcurrentHashmap引用了锁分割,将map分割为16部分(默认初始容量为16),由不同的锁控制;不过,尽管所有操作都是线程安全的,获取操作不 必锁定,不支持某种以所有访问的方式锁定整个表,CHM不会锁住整个MapConcurrentHashmap 要比Map m = Collections.synchronizedMap(new HashMap(...)); 方法
和hashtable 效率相对较高(应用场景:读取多于写入);
没有更多推荐了,}

我要回帖

更多关于 api get 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信