Hashtable源码分析

1、Hashtable是线程安全的,采用全量加锁的方式控制多线程并发访问

2、不允许null键和null值(HashMap可以接受为null的键值(key)和值(value))

3、一次仅能有一个对象来读取和修改Hashtable,每个线程要获取或修改都要先拿到同步锁,其他线程要等待同步锁被释放之后才能再次获取同步锁去读取和更新Hashtable

构造方法:

// 默认初始容量是11   
 public Hashtable() {
        this(11, 0.75f);
    }
// 带参构造
    public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
      // 初始化哈希表
        table = new Entry<?,?>[initialCapacity];
      // 阀值为初始容量乘负载因子和Integer.MAX_VALUE - 7之间的最小者
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }

get方法,put方法,remove方法等对Hashtable进行读取和修改的方法都是同步方法,锁的是Hashtable对象,因此多线程共享一个hashtable对象时,同一时刻只有一个线程能读取和修改Hashtable

    @SuppressWarnings("unchecked")
    public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        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 (V)e.value;
            }
        }
        return null;
    }

    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;
    }

hashtable put数据时候可以get数据吗?
  多个线程共享一个hashtable对象时,一个get时,另一个不能put。
成员方法中,synchronized锁住的是对象this,只有调用同一个对象的方法才需要获取锁。同时,同一个对象中所有加了synchronize的方法只能一次调 用一个,所以不能。
静态方法中,synchronized锁的是整个类对象,类似于(X.class),该类中所有加了synchronized的静态方法,一次只能调用一个。

验证:

public class HashTable {

    private Map<String, String> map = new HashMap();

    public synchronized String get(String key) {
        System.out.println("get开始");
        String value = map.get(key);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("get结束");
        return value;
    }

    public synchronized String put(String key, String value) {
        System.out.println("put开始");
        String oldValue = map.put(key, value);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("put结束");
        return oldValue;
    }
}

public static void main(String[] args) {
        final HashTable hashTable = new HashTable();
        new Thread(new Runnable() {
//            HashTable hashTable = new HashTable();

            @Override
            public void run() {
                hashTable.get("name");
            }
        }).start();
        new Thread(new Runnable() {
//            HashTable hashTable = new HashTable();

            @Override
            public void run() {
                hashTable.put("name", "yangyongjie");
            }
        }).start();
    }

get开始
get结束
put开始
put结束
可以看到不同的同步方法时顺序执行的。
原文地址:https://www.cnblogs.com/yangyongjie/p/10978833.html