Java集合-Hashtable的实现原理

1、概述

  HashTable是一个线程安全的哈希表,它通过使用synchronized关键字对方法进行加锁,从而保证了线程安全,但这也导致了在单线程环境中效率低下等问题。HashTable与HashMap不同,他不允许插入null值和null键。

2、属性

  //哈希表
    private transient Entry<?,?>[] table;
  
   //记录哈希表中键值对的个数
    private transient int count;

   //扩容的阈值
    private int threshold;

  //负载因子
    private float loadFactor;

3、方法

构造方法

public Hashtable(intinitialCapacity, floatloadFactor) {....}
public Hashtable(intinitialCapacity) {
        this(initialCapacity, 0.75f);
}        
public Hashtable() {
        this(11, 0.75f);
    }        

从构造函数中,我们可以获取到这些信息:HashTable默认的初始容量为11(与HashMap不同)。负载因子默认为0.75(与HashMap相同)而正因为默认初始化容量的不同,同时也没有对容量做调整的策略,所以可以先推断出,Hashtable使用的哈希函数跟HashMap是不一样的

get方法

  跟HashMap相比,Hashtableget方法非常简单。get方法使用了synchronized来修饰,所以它能保证线程安全。并且它是通过链表的方式来处理冲突的。另外,HashTable并没有像HashMap那样封装一个哈希函数,而是直接把哈希函数写在了方法中。而哈希函数也是比较简单的,它仅对哈希表的长度进行了取模。

put方法

  put方法一开始就表明了不能有null值,否则就会抛出一个空指针异常。Hashtableput方法也是使用synchronized来修饰。在Hashtable中,几乎所有的方法都使用了synchronized来保证线程安全。

rehash方法

   protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // 扩容为原来的两倍+1
        int newCapacity = (oldCapacity << 1) + 1;
    // 判断是否超过最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; } Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++;
      // 计算下一次rehash的阈值 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; } } }

  Hashtablerehash方法相当于HashMapresize方法。跟HashMap那种巧妙的rehash方式相比,Hashtablerehash过程需要对每个键值对都重新计算哈希值,而比起异或和与操作,取模是一个非常耗时的操作,所以这也是导致效率较低的原因之一

  

猜你喜欢

转载自www.cnblogs.com/lgh544/p/12900397.html
今日推荐