diff --git a/CHANGELOG.md b/CHANGELOG.md index f6a51fd13..bb00d6dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * 【core 】 修正LocalDateTimeUtil.offset方法注释问题(issue#I2EEXC@Gitee) * 【extra 】 VelocityEngine的getRowEngine改为getRawEngine(issue#I2EGRG@Gitee) * 【cache 】 缓存降低锁的粒度,提高并发能力(pr#1385@Github) +* 【core 】 SimpleCache缓存降低锁的粒度,提高并发能力(pr#1385@Github) ### Bug修复 * 【core 】 修复FileUtil.move以及PathUtil.copy等无法自动创建父目录的问题(issue#I2CKTI@Gitee) diff --git a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java index 2e348380a..f1c3ba7bf 100644 --- a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java +++ b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java @@ -150,7 +150,7 @@ public abstract class AbstractCache implements Cache { final Lock keyLock = keyLockMap.computeIfAbsent(key, k -> new ReentrantLock()); keyLock.lock(); try { - // 双重检查锁 + // 双重检查锁,防止在竞争锁的过程中已经有其它线程写入 final CacheObj co = cacheMap.get(key); if (null == co || co.isExpired()) { try { diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java b/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java index b1bd36c88..fcb407231 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java @@ -6,6 +6,9 @@ import java.io.Serializable; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** @@ -24,6 +27,10 @@ public class SimpleCache implements Iterable>, Serializabl private final Map cache; // 乐观读写锁 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + /** + * 写的时候每个key一把锁,降低锁的粒度 + */ + protected final Map keyLockMap = new ConcurrentHashMap<>(); /** * 构造,默认使用{@link WeakHashMap}实现缓存自动清理 @@ -70,22 +77,24 @@ public class SimpleCache implements Iterable>, Serializabl */ public V get(K key, Func0 supplier) { V v = get(key); - if(null == v && null != supplier){ - lock.writeLock().lock(); - try{ - v = cache.get(key); + //每个key单独获取一把锁,降低锁的粒度提高并发能力,see pr#1385@Github + final Lock keyLock = keyLockMap.computeIfAbsent(key, k -> new ReentrantLock()); + keyLock.lock(); + try { // 双重检查,防止在竞争锁的过程中已经有其它线程写入 + v = cache.get(key); if (null == v) { try { v = supplier.call(); } catch (Exception e) { throw new RuntimeException(e); } - cache.put(key, v); + put(key, v); } - } finally{ - lock.writeLock().unlock(); + } finally { + keyLock.unlock(); + keyLockMap.remove(key); } } @@ -143,4 +152,4 @@ public class SimpleCache implements Iterable>, Serializabl public Iterator> iterator() { return this.cache.entrySet().iterator(); } -} \ No newline at end of file +}