面试题答案
一键面试- 线程安全实现方式:
Hashtable
通过在几乎所有的关键方法(如put
、get
、remove
等)上使用synchronized
关键字来实现线程安全。这意味着当一个线程调用这些方法时,它会获取对象的锁,其他线程必须等待锁的释放才能调用相同的方法,从而避免了多线程同时访问导致的数据不一致问题。
- 关键技术点和方法:
-
put
方法:public synchronized V put(K key, V value) { // 确保键不为空 if (value == null) { throw new NullPointerException(); } // 计算键的哈希值 Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; // 遍历链表查找键是否存在 for (Entry<K,V> e = (Entry<K,V>)tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V old = e.value; e.value = value; return old; } } // 键不存在则插入新的键值对 addEntry(hash, key, value, index); return null; }
- 该方法使用
synchronized
关键字修饰,确保在多线程环境下只有一个线程能够执行插入操作,避免了不同线程同时插入导致哈希表结构损坏等问题。
- 该方法使用
-
get
方法:public synchronized V get(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = (Entry<K,V>)tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; }
- 同样使用
synchronized
关键字,保证在多线程环境下,获取值的操作是线程安全的,不会出现读取到不一致数据的情况。
- 同样使用
-
remove
方法:public synchronized V remove(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = (Entry<K,V>)tab[index], prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } V oldValue = e.value; e.value = null; count--; return oldValue; } } return null; }
- 此方法也是通过
synchronized
关键字来保证删除操作在多线程环境下的线程安全性,防止多个线程同时删除导致哈希表结构混乱。
- 此方法也是通过
-
整体性能影响:虽然
synchronized
关键字实现了线程安全,但是由于所有关键方法都被同步,这在高并发场景下会导致性能瓶颈,因为同一时间只能有一个线程访问Hashtable
的关键方法,其他线程需要等待锁的释放,从而降低了系统的并发处理能力。这也是后来出现ConcurrentHashMap
等更高效的线程安全哈希表的原因之一。
-