COW 的思想
思想的通用性
CopyOnWriteArrayList 和 CopyOnWriteArraySet 这种读写分离的思想是通用的。
今天就让我们用这种思想实现一个简单的工具:CopyOnWriteHashMap。
实践出真知
这个工具包都出来几十年了,还是用的人很少。
要学以致用,站在巨人的肩膀上,
自己实现一个 copyOnWriteMap
类定义
public class CopyOnWriteHashMap<K,V> implements Map<K, V>, Cloneable {
/**
* 内部 HashMap
* @since 0.0.4
*/
private volatile Map<K, V> internalMap;
/**
* 可重入锁
* @since 0.0.4
*/
private final ReentrantLock lock;
/**
* 无参构造器
*
* 初始化对应的属性
* @since 0.0.4
*/
public CopyOnWriteHashMap() {
this.internalMap = new HashMap<K, V>();
this.lock = new ReentrantLock();
}
}
我们实现 Map接口,内部声明 internalMap 用于复用 HashMap 的方法,使用 lock 锁保证并发安全。
无参构造器,就是对属性进行简单的初始化。
核心方法
put 方法
我们通过并发加锁,并且拷贝一份 internalMap 的方式,实现 put 操作。
@Override
public V put(K key, V value) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 拷贝一份
Map<K, V> newMap = new HashMap<>(internalMap);
V val = newMap.put(key, value);
// 设置为新的
internalMap = newMap;
return val;
} finally {
lock.unlock();
}
}
putAll 方法
根据一个集合进行初始化。
@Override
public void putAll(Map<? extends K, ? extends V> m) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 拷贝一份
Map<K, V> newMap = new HashMap<>(internalMap);
newMap.putAll(m);
// 设置为新的
internalMap = newMap;
} finally {
lock.unlock();
}
}
remove 操作
这个实现也是类似的。
@Override
public V remove(Object key) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 拷贝一份
Map<K, V> newMap = new HashMap<>(internalMap);
V val = newMap.remove(key);
// 设置为新的
internalMap = newMap;
return val;
} finally {
lock.unlock();
}
}
clear 清空操作
@Override
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
internalMap.clear();
} finally {
lock.unlock();
}
}
整体实现
一个完整版本的实现如下:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
/**
* COW HashMap
* @author 老马啸西风
* @since 0.0.4
* @param <K> key
* @param <V> value
*/
public class CopyOnWriteHashMap<K,V> implements Map<K, V>, Cloneable {
/**
* 内部 HashMap
* @since 0.0.4
*/
private volatile Map<K, V> internalMap;
/**
* 可重入锁
* @since 0.0.4
*/
private final ReentrantLock lock;
/**
* 无参构造器
*
* 初始化对应的属性
* @since 0.0.4
*/
public CopyOnWriteHashMap() {
this.internalMap = new HashMap<K, V>();
this.lock = new ReentrantLock();
}
@Override
public int size() {
return internalMap.size();
}
@Override
public boolean isEmpty() {
return internalMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return internalMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return internalMap.containsValue(value);
}
@Override
public V get(Object key) {
return internalMap.get(key);
}
@Override
public V put(K key, V value) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 拷贝一份
Map<K, V> newMap = new HashMap<>(internalMap);
V val = newMap.put(key, value);
// 设置为新的
internalMap = newMap;
return val;
} finally {
lock.unlock();
}
}
@Override
public V remove(Object key) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 拷贝一份
Map<K, V> newMap = new HashMap<>(internalMap);
V val = newMap.remove(key);
// 设置为新的
internalMap = newMap;
return val;
} finally {
lock.unlock();
}
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 拷贝一份
Map<K, V> newMap = new HashMap<>(internalMap);
newMap.putAll(m);
// 设置为新的
internalMap = newMap;
} finally {
lock.unlock();
}
}
@Override
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
internalMap.clear();
} finally {
lock.unlock();
}
}
@Override
public Set<K> keySet() {
return internalMap.keySet();
}
@Override
public Collection<V> values() {
return internalMap.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return internalMap.entrySet();
}
}
小结
这个简易版本的 COW HashMap 只是老马的一个简单实践,还有很多可以改进的饿地方。
各位小伙伴感兴趣的话,可以利用 COW 这种思想,事项更多属于自己的 COW 集合。
希望本文对你有帮助,如果有其他想法的话,也可以评论区和大家分享哦。
各位极客的点赞收藏转发,是老马持续写作的最大动力!
参考资料
jdk8