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)
|
* 【core 】 IterUtil添加List转Map的工具方法(pr#123@Gitee)
|
||||||
|
|
||||||
### Bug修复
|
### Bug修复
|
||||||
|
* 【core 】 修复SimpleCache死锁问题(issue#I1HOKB@Gitee)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import java.io.Serializable;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.locks.StampedLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 简单缓存,无超时实现,默认使用{@link WeakHashMap}实现缓存自动清理
|
* 简单缓存,无超时实现,默认使用{@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 Map<K, V> cache;
|
||||||
// 乐观读写锁
|
// 乐观读写锁
|
||||||
private final StampedLock lock = new StampedLock();
|
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造,默认使用{@link WeakHashMap}实现缓存自动清理
|
* 构造,默认使用{@link WeakHashMap}实现缓存自动清理
|
||||||
@ -53,11 +53,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
|||||||
* @return 值
|
* @return 值
|
||||||
*/
|
*/
|
||||||
public V get(K key) {
|
public V get(K key) {
|
||||||
long stamp = lock.readLock();
|
lock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
return cache.get(key);
|
return cache.get(key);
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlockRead(stamp);
|
lock.readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,23 +69,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
|||||||
* @return 值对象
|
* @return 值对象
|
||||||
*/
|
*/
|
||||||
public V get(K key, Func0<V> supplier) {
|
public V get(K key, Func0<V> supplier) {
|
||||||
if (null == supplier) {
|
V v = get(key);
|
||||||
return get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
long stamp = lock.readLock();
|
if(null == v && null != supplier){
|
||||||
V v;
|
lock.writeLock().lock();
|
||||||
try{
|
try{
|
||||||
v = cache.get(key);
|
|
||||||
if (null == v) {
|
|
||||||
// 尝试转换独占写锁
|
|
||||||
long writeStamp = lock.tryConvertToWriteLock(stamp);
|
|
||||||
if (0 == writeStamp) {
|
|
||||||
// 转换失败,手动更新为写锁
|
|
||||||
lock.unlockRead(stamp);
|
|
||||||
writeStamp = lock.writeLock();
|
|
||||||
}
|
|
||||||
stamp = writeStamp;
|
|
||||||
v = cache.get(key);
|
v = cache.get(key);
|
||||||
// 双重检查,防止在竞争锁的过程中已经有其它线程写入
|
// 双重检查,防止在竞争锁的过程中已经有其它线程写入
|
||||||
if (null == v) {
|
if (null == v) {
|
||||||
@ -96,10 +84,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
|||||||
}
|
}
|
||||||
cache.put(key, v);
|
cache.put(key, v);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} finally{
|
} finally{
|
||||||
lock.unlock(stamp);
|
lock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return v;
|
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) {
|
public V put(K key, V value) {
|
||||||
// 独占写锁
|
// 独占写锁
|
||||||
final long stamp = lock.writeLock();
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
cache.put(key, value);
|
cache.put(key, value);
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlockWrite(stamp);
|
lock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -129,11 +118,11 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
|||||||
*/
|
*/
|
||||||
public V remove(K key) {
|
public V remove(K key) {
|
||||||
// 独占写锁
|
// 独占写锁
|
||||||
final long stamp = lock.writeLock();
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
return cache.remove(key);
|
return cache.remove(key);
|
||||||
} finally {
|
} 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() {
|
public void clear() {
|
||||||
// 独占写锁
|
// 独占写锁
|
||||||
final long stamp = lock.writeLock();
|
lock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
this.cache.clear();
|
this.cache.clear();
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlockWrite(stamp);
|
lock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,4 +23,19 @@ public interface Func<P, R> {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
R call(P... parameters) throws Exception;
|
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 自定义异常
|
* @throws Exception 自定义异常
|
||||||
*/
|
*/
|
||||||
R call() 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 自定义异常
|
* @throws Exception 自定义异常
|
||||||
*/
|
*/
|
||||||
R call(P parameter) 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")
|
@SuppressWarnings("unchecked")
|
||||||
void call(P... parameters) throws Exception;
|
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 自定义异常
|
* @throws Exception 自定义异常
|
||||||
*/
|
*/
|
||||||
void call() 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 自定义异常
|
* @throws Exception 自定义异常
|
||||||
*/
|
*/
|
||||||
void call(P parameter) 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.exceptions.UtilException;
|
||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class SingletonTest {
|
public class SingletonTest {
|
||||||
@ -27,4 +28,24 @@ public class SingletonTest {
|
|||||||
private String name;
|
private String name;
|
||||||
private String age;
|
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