Hashtable
Hashtable
Hashtable:线程安全的,不允许null的键或值;是线程安全的,但是Hashtable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁。多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差
1、Hashtable不允许null值或者null键,编译时不会报错,但是运行报错。HashMap允许null值或者null键,只是key为null只能一次,value为null没有限制
2、HashMap的实现上没有同步约束,但是Hashtable的实现方法上有synchronized同步约束,所以说Hashtabe属于一个线程安全的类
由于线程安全,则在非多线程环境下不建议使用
类定义
Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。通过拉链法实现的哈希表
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
数据存储
具体数据存放还是拉链法,也有加载因子参数
构造器
public Hashtable(){
this(11,0.75f)
}
默认容积值为11,默认加载因子为0.75
public Hashtable(int initialCapacity){
this(initialCapacity,0.75f)
}
允许设置初始化容积值,默认加载因子为0.75
直接按照初始化容积值构建桶的数组,HashMap是在第一次使用时才进行数组的初始化操作
扩容阈值=(int)(初始化容积*加载因子)
新增元素的方法实现
这里的value和key不允许为空
获取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
添加元素采用的是头插法
rehash操作的实现
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
int newCapacity = (oldCapacity << 1) + 1; 新数组的容积为原始容积*2+1
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
return;
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];新建数组
modCount++; 修改次数+1,主要用于判断遍历数据时不同同时修改结构
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;//使用新建树
//遍历原始集合中的所有元素,从新计算每个节点的位置
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.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}