面试题答案
一键面试设计思路
- 线程安全:采用分段锁机制,对不同的数据段进行锁定,从而允许不同线程同时访问不同的数据段,减少锁竞争。
- 分段锁设计:将哈希表分成多个段(Segment),每个段有自己独立的锁。当对某个键值对进行操作时,首先通过哈希算法确定该键值对属于哪个段,然后获取该段的锁进行操作。
- 处理哈希冲突:采用链地址法,即每个哈希桶(bucket)是一个链表,当发生哈希冲突时,将新的节点添加到链表末尾。
核心代码示例
import java.util.concurrent.locks.ReentrantLock;
class MyConcurrentHashMap<K, V> {
private static final int DEFAULT_SEGMENTS = 16;
private final Segment<K, V>[] segments;
public MyConcurrentHashMap() {
this.segments = new Segment[DEFAULT_SEGMENTS];
for (int i = 0; i < DEFAULT_SEGMENTS; i++) {
segments[i] = new Segment<>();
}
}
private static class Segment<K, V> {
private final ReentrantLock lock = new ReentrantLock();
private final HashEntry<K, V>[] table;
@SuppressWarnings("unchecked")
Segment() {
table = new HashEntry[16];
}
V put(K key, V value) {
lock.lock();
try {
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % table.length;
for (HashEntry<K, V> e = table[index]; e != null; e = e.next) {
if (e.key.equals(key)) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
HashEntry<K, V> newEntry = new HashEntry<>(key, value, table[index]);
table[index] = newEntry;
return null;
} finally {
lock.unlock();
}
}
V get(K key) {
lock.lock();
try {
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % table.length;
for (HashEntry<K, V> e = table[index]; e != null; e = e.next) {
if (e.key.equals(key)) {
return e.value;
}
}
return null;
} finally {
lock.unlock();
}
}
}
private static class HashEntry<K, V> {
final K key;
V value;
HashEntry<K, V> next;
HashEntry(K key, V value, HashEntry<K, V> next) {
this.key = key;
this.value = value;
this.next = next;
}
}
public V put(K key, V value) {
int segmentIndex = (key.hashCode() & 0x7FFFFFFF) % segments.length;
return segments[segmentIndex].put(key, value);
}
public V get(K key) {
int segmentIndex = (key.hashCode() & 0x7FFFFFFF) % segments.length;
return segments[segmentIndex].get(key);
}
}
可以通过以下方式测试:
public class TestMyConcurrentHashMap {
public static void main(String[] args) {
MyConcurrentHashMap<String, Integer> map = new MyConcurrentHashMap<>();
map.put("key1", 1);
System.out.println(map.get("key1"));
}
}
在上述代码中:
MyConcurrentHashMap
类包含一个Segment
数组,每个Segment
管理一部分哈希表数据。Segment
类使用ReentrantLock
实现锁机制,并且包含一个HashEntry
数组用于存储键值对,通过链地址法处理哈希冲突。HashEntry
类表示哈希表中的节点,包含键、值和指向下一个节点的引用。put
和get
方法首先确定要操作的Segment
,然后调用Segment
相应的方法进行操作。