fix dead lock bug

This commit is contained in:
Looly 2020-05-19 18:31:30 +08:00
parent 008855fafb
commit f7bf950073
9 changed files with 125 additions and 29 deletions

View File

@ -15,6 +15,7 @@
* 【core 】 IterUtil添加List转Map的工具方法pr#123@Gitee
### Bug修复
* 【core 】 修复SimpleCache死锁问题issue#I1HOKB@Gitee
-------------------------------------------------------------------------------------------------------------

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}