add LockUtil and fix Cache

This commit is contained in:
Looly
2020-03-26 23:46:36 +08:00
parent 54760ea0a2
commit 0d7ef8f092
13 changed files with 379 additions and 218 deletions

View File

@@ -6,9 +6,7 @@ import cn.hutool.core.lang.func.Func0;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import java.util.concurrent.locks.StampedLock;
/**
* 超时和限制大小的缓存的默认实现<br>
@@ -17,32 +15,39 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
* <li>创建一个新的Map</li>
* <li>实现 <code>prune</code> 策略</li>
* </ul>
*
* @author Looly,jodd
*
* @param <K> 键类型
* @param <V> 值类型
* @author Looly, jodd
*/
public abstract class AbstractCache<K, V> implements Cache<K, V> {
private static final long serialVersionUID = 1L;
protected Map<K, CacheObj<K, V>> cacheMap;
private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
private final ReadLock readLock = cacheLock.readLock();
private final WriteLock writeLock = cacheLock.writeLock();
private final StampedLock lock = new StampedLock();
/** 返回缓存容量,<code>0</code>表示无大小限制 */
/**
* 返回缓存容量,<code>0</code>表示无大小限制
*/
protected int capacity;
/** 缓存失效时长, <code>0</code> 表示无限制,单位毫秒 */
/**
* 缓存失效时长, <code>0</code> 表示无限制,单位毫秒
*/
protected long timeout;
/** 每个对象是否有单独的失效时长,用于决定清理过期对象是否有必要。 */
/**
* 每个对象是否有单独的失效时长,用于决定清理过期对象是否有必要。
*/
protected boolean existCustomTimeout;
/** 命中数 */
/**
* 命中数
*/
protected int hitCount;
/** 丢失数 */
/**
* 丢失数
*/
protected int missCount;
// ---------------------------------------------------------------- put start
@@ -53,20 +58,19 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
@Override
public void put(K key, V object, long timeout) {
writeLock.lock();
final long stamp = lock.writeLock();
try {
putWithoutLock(key, object, timeout);
} finally {
writeLock.unlock();
lock.unlockWrite(stamp);
}
}
/**
* 加入元素,无锁
*
* @param key 键
* @param object 值
*
* @param key
* @param object
* @param timeout 超时时长
* @since 4.5.16
*/
@@ -85,8 +89,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
// ---------------------------------------------------------------- get start
@Override
public boolean containsKey(K key) {
readLock.lock();
final long stamp = lock.readLock();
try {
// 不存在或已移除
final CacheObj<K, V> co = cacheMap.get(key);
@@ -99,7 +102,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
return true;
}
} finally {
readLock.unlock();
lock.unlockRead(stamp);
}
// 过期
@@ -111,24 +114,14 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
* @return 命中数
*/
public int getHitCount() {
this.readLock.lock();
try {
return hitCount;
} finally {
this.readLock.unlock();
}
return hitCount;
}
/**
* @return 丢失数
*/
public int getMissCount() {
this.readLock.lock();
try {
return missCount;
} finally {
this.readLock.unlock();
}
return missCount;
}
@Override
@@ -140,11 +133,11 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
public V get(K key, Func0<V> supplier) {
V v = get(key);
if (null == v && null != supplier) {
writeLock.lock();
final long stamp = lock.writeLock();
try {
// 双重检查锁
final CacheObj<K, V> co = cacheMap.get(key);
if(null == co || co.isExpired() || null == co.getValue()) {
if (null == co || co.isExpired()) {
try {
v = supplier.call();
} catch (Exception e) {
@@ -155,7 +148,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
v = co.get(true);
}
} finally {
writeLock.unlock();
lock.unlockWrite(stamp);
}
}
return v;
@@ -163,23 +156,25 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
@Override
public V get(K key, boolean isUpdateLastAccess) {
readLock.lock();
// 尝试读取缓存,使用乐观读锁
long stamp = lock.readLock();
try {
// 不存在或已移除
final CacheObj<K, V> co = cacheMap.get(key);
if (co == null) {
if (null == co) {
missCount++;
return null;
}
if (false == co.isExpired()) {
if (co.isExpired()) {
missCount++;
} else{
// 命中
hitCount++;
return co.get(isUpdateLastAccess);
}
} finally {
readLock.unlock();
lock.unlock(stamp);
}
// 过期
@@ -199,30 +194,32 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
@Override
public Iterator<CacheObj<K, V>> cacheObjIterator() {
CopiedIter<CacheObj<K, V>> copiedIterator;
readLock.lock();
final long stamp = lock.readLock();
try {
copiedIterator = CopiedIter.copyOf(this.cacheMap.values().iterator());
} finally {
readLock.unlock();
lock.unlockRead(stamp);
}
return new CacheObjIterator<>(copiedIterator);
}
// ---------------------------------------------------------------- prune start
/**
* 清理实现
*
* 清理实现<br>
* 子类实现此方法时无需加锁
*
* @return 清理数
*/
protected abstract int pruneCache();
@Override
public final int prune() {
writeLock.lock();
final long stamp = lock.writeLock();
try {
return pruneCache();
} finally {
writeLock.unlock();
lock.unlockWrite(stamp);
}
}
// ---------------------------------------------------------------- prune end
@@ -235,7 +232,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
/**
* @return 默认缓存失效时长。<br>
* 每个对象可以单独设置失效时长
* 每个对象可以单独设置失效时长
*/
@Override
public long timeout() {
@@ -244,26 +241,16 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
/**
* 只有设置公共缓存失效时长或每个对象单独的失效时长时清理可用
*
*
* @return 过期对象清理是否可用,内部使用
*/
protected boolean isPruneExpiredActive() {
this.readLock.lock();
try {
return (timeout != 0) || existCustomTimeout;
} finally {
this.readLock.unlock();
}
return (timeout != 0) || existCustomTimeout;
}
@Override
public boolean isFull() {
this.readLock.lock();
try {
return (capacity > 0) && (cacheMap.size() >= capacity);
} finally {
this.readLock.unlock();
}
return (capacity > 0) && (cacheMap.size() >= capacity);
}
@Override
@@ -273,49 +260,34 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
@Override
public void clear() {
writeLock.lock();
final long stamp = lock.writeLock();
try {
cacheMap.clear();
} finally {
writeLock.unlock();
lock.unlockWrite(stamp);
}
}
@Override
public int size() {
this.readLock.lock();
try {
return cacheMap.size();
} finally {
this.readLock.unlock();
}
return cacheMap.size();
}
@Override
public boolean isEmpty() {
this.readLock.lock();
try {
return cacheMap.isEmpty();
} finally {
this.readLock.unlock();
}
return cacheMap.isEmpty();
}
@Override
public String toString() {
this.readLock.lock();
try {
return this.cacheMap.toString();
} finally {
this.readLock.unlock();
}
return this.cacheMap.toString();
}
// ---------------------------------------------------------------- common end
/**
* 对象移除回调。默认无动作
*
* @param key 键
*
* @param key
* @param cachedObject 被缓存的对象
*/
protected void onRemove(K key, V cachedObject) {
@@ -324,27 +296,27 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
/**
* 移除key对应的对象
*
* @param key 键
*
* @param key
* @param withMissCount 是否计数丢失数
*/
private void remove(K key, boolean withMissCount) {
writeLock.lock();
final long stamp = lock.writeLock();
CacheObj<K, V> co;
try {
co = removeWithoutLock(key, withMissCount);
} finally {
writeLock.unlock();
lock.unlockWrite(stamp);
}
if (null != co) {
onRemove(co.key, co.obj);
}
}
/**
* 移除key对应的对象不加锁
*
* @param key 键
*
* @param key
* @param withMissCount 是否计数丢失数
* @return 移除的对象无返回null
*/