读Java 11 源码(4)Hashtable

数据存在那?一个用Entry为元素的数组。

private transient Entry<?,?>[] table;

table,这个是由Entry这个内部类组成的数组,我们来看看这个类的代码。

private static class Entry<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
	//(壹)
    Entry<K,V> next;

    protected Entry(int hash, K key, V value, Entry<K,V> next) {
        this.hash = hash;
        this.key =  key;
        this.value = value;
        this.next = next;
    }

    @SuppressWarnings("unchecked")
    protected Object clone() {
        return new Entry<>(hash, key, value,
                              (next==null ? null : (Entry<K,V>) next.clone()));
    }

    // Map.Entry Ops
  public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    public V setValue(V value) {
        if (value == null)
            throw new NullPointerException();

        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry<?,?>)o;

        return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
           (value==null ? e.getValue()==null : value.equals(e.getValue()));
    }

    public int hashCode() {
        return hash ^ Objects.hashCode(value);
    }

    public String toString() {
        return key.toString()+"="+value.toString();
    }
}

这里代码挺多,但是值得看的没几个,首先就是在(壹)的声明,可以看出,这个带着next节点的,可以组成一个链表。

还有就是equals方法的代码:

return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
	(value==null ? e.getValue()==null : value.equals(e.getValue()));

可以看出,key和value都要进行equals。

如果只是put() 操作,会导致modcount的更改么?

这个需呀看情况哦,如果当前的key已经存在了,值得是有个index的相同,对象可以equals的key,已经在table里了。那么就会执行put操作,(主要还是替换value)。
如果没有,就是hashcode不同,这种,那么要修改modCount。

Hashtable 为什么是线程安全的?

因为每个操作都用synchronized这个修饰了,这个同步的操作是由JVM完成的,至于说它到底是怎么实现的,我们这里不做深究,这个值得重新在写一篇来专门的探讨探讨,比如put()操作:

public synchronized V put(K key, V value) {
    // Make sure the value is not null
  if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
  Entry<?,?> tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[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(hash, key, value, index);
    return null;
}

之所以是线程安全的,因为当多个线程调用,希望去同时修改(比如put,remove这些)这个对象的时候,因为这些方法被synchronized这个关键词修饰,所以每次只能有一个线程得到修改这个对象的权限,其他的线程只能等待。这样就保证了线程安全。

优点

线程安全,这个就是这个类唯一的优点了

缺点

性能不行,在高并发的环境下,对象只能每次被一个类修改,如果在大量的并发量的前提下,会导致大量的线程进入等待,很消耗资源,线程之间的频繁切换很消耗CPU的资源。我们现在一般都是多核处理器,这种处理方式依然是单核来解决这种高并发的问题,如果可以多个线程同时操作一个对象,而且不会有线程安全问题,这样方案无疑就很nice了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章