mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix dead lock bug
This commit is contained in:
parent
008855fafb
commit
f7bf950073
@ -15,6 +15,7 @@
|
||||
* 【core 】 IterUtil添加List转Map的工具方法(pr#123@Gitee)
|
||||
|
||||
### Bug修复
|
||||
* 【core 】 修复SimpleCache死锁问题(issue#I1HOKB@Gitee)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -6,7 +6,7 @@ import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.locks.StampedLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* 简单缓存,无超时实现,默认使用{@link WeakHashMap}实现缓存自动清理
|
||||
@ -23,7 +23,7 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
*/
|
||||
private final Map<K, V> cache;
|
||||
// 乐观读写锁
|
||||
private final StampedLock lock = new StampedLock();
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
/**
|
||||
* 构造,默认使用{@link WeakHashMap}实现缓存自动清理
|
||||
@ -53,11 +53,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
* @return 值
|
||||
*/
|
||||
public V get(K key) {
|
||||
long stamp = lock.readLock();
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return cache.get(key);
|
||||
} finally {
|
||||
lock.unlockRead(stamp);
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,23 +69,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
* @return 值对象
|
||||
*/
|
||||
public V get(K key, Func0<V> supplier) {
|
||||
if (null == supplier) {
|
||||
return get(key);
|
||||
}
|
||||
V v = get(key);
|
||||
|
||||
long stamp = lock.readLock();
|
||||
V v;
|
||||
try {
|
||||
v = cache.get(key);
|
||||
if (null == v) {
|
||||
// 尝试转换独占写锁
|
||||
long writeStamp = lock.tryConvertToWriteLock(stamp);
|
||||
if (0 == writeStamp) {
|
||||
// 转换失败,手动更新为写锁
|
||||
lock.unlockRead(stamp);
|
||||
writeStamp = lock.writeLock();
|
||||
}
|
||||
stamp = writeStamp;
|
||||
if(null == v && null != supplier){
|
||||
lock.writeLock().lock();
|
||||
try{
|
||||
v = cache.get(key);
|
||||
// 双重检查,防止在竞争锁的过程中已经有其它线程写入
|
||||
if (null == v) {
|
||||
@ -96,10 +84,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
}
|
||||
cache.put(key, v);
|
||||
}
|
||||
} finally{
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock(stamp);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -112,11 +101,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
*/
|
||||
public V put(K key, V value) {
|
||||
// 独占写锁
|
||||
final long stamp = lock.writeLock();
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
cache.put(key, value);
|
||||
} finally {
|
||||
lock.unlockWrite(stamp);
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -129,11 +118,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
*/
|
||||
public V remove(K key) {
|
||||
// 独占写锁
|
||||
final long stamp = lock.writeLock();
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
return cache.remove(key);
|
||||
} finally {
|
||||
lock.unlockWrite(stamp);
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,11 +131,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
*/
|
||||
public void clear() {
|
||||
// 独占写锁
|
||||
final long stamp = lock.writeLock();
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
this.cache.clear();
|
||||
} finally {
|
||||
lock.unlockWrite(stamp);
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,4 +23,19 @@ public interface Func<P, R> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
R call(P... parameters) throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @param parameters 参数列表
|
||||
* @return 函数执行结果
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default R callWithRuntimeException(P... parameters){
|
||||
try {
|
||||
return call(parameters);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,4 +20,18 @@ public interface Func0<R> {
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
R call() throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @return 函数执行结果
|
||||
* @since 5.3.6
|
||||
*/
|
||||
default R callWithRuntimeException(){
|
||||
try {
|
||||
return call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,4 +23,19 @@ public interface Func1<P, R> {
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
R call(P parameter) throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @param parameter 参数
|
||||
* @return 函数执行结果
|
||||
* @since 5.3.6
|
||||
*/
|
||||
default R callWithRuntimeException(P parameter){
|
||||
try {
|
||||
return call(parameter);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,18 @@ public interface VoidFunc<P> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
void call(P... parameters) throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @param parameters 参数列表
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default void callWithRuntimeException(P... parameters){
|
||||
try {
|
||||
call(parameters);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,4 +19,17 @@ public interface VoidFunc0 {
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
void call() throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @since 5.3.6
|
||||
*/
|
||||
default void callWithRuntimeException(){
|
||||
try {
|
||||
call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,4 +20,18 @@ public interface VoidFunc1<P> {
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
void call(P parameter) throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @param parameter 参数
|
||||
* @since 5.3.6
|
||||
*/
|
||||
default void callWithRuntimeException(P parameter){
|
||||
try {
|
||||
call(parameter);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package cn.hutool.core.lang;
|
||||
import cn.hutool.core.exceptions.UtilException;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import lombok.Data;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SingletonTest {
|
||||
@ -27,4 +28,24 @@ public class SingletonTest {
|
||||
private String name;
|
||||
private String age;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试单例构建属性锁死问题
|
||||
* C构建单例时候,同时构建B,此时在SimpleCache中会有写锁竞争(写入C时获取了写锁,此时要写入B,也要获取写锁)
|
||||
*/
|
||||
@Test(timeout = 1000L)
|
||||
public void reentrantTest(){
|
||||
final C c = Singleton.get(C.class);
|
||||
Assert.assertEquals("aaa", c.getB().getA());
|
||||
}
|
||||
|
||||
@Data
|
||||
static class B{
|
||||
private String a = "aaa";
|
||||
}
|
||||
|
||||
@Data
|
||||
static class C{
|
||||
private B b = Singleton.get(B.class);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user