为什么要减小lock的粒度
jvm的lock对象锁是代码块级别,粒度太大,如果使用redis做锁,对于单体项目来说杀鸡用牛刀!
不多说上代码
代码
这个接口 是用来执行真正的业务
/**
* 锁函数
*
* @author LeiHeng
*/
public interface LockFunction {
/**
* 执行方法
*/
void execute();
}
上锁工具类的接口,之所以用接口,方便以后替换redis做锁
/**
* 上锁工具类
*
* @author LeiHeng
*/
public interface LockUtil {
/**
* 上锁
*
* @param key 上锁的key
* @param lockFunction 执行的函数
* @return 是否上锁成功
*/
boolean lockAndExecute(String key, LockFunction lockFunction);
}
锁工具类的实现接口
package com.zombies.pixel.business.utils.lock.impl;
import com.zombies.pixel.business.utils.lock.LockFunction;
import com.zombies.pixel.business.utils.lock.LockUtil;
import com.zombies.pixel.common.utils.OptionalTactics;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @ClassName: LockUtilImpl
* @Description: 上锁工具类实现类
* @author: LeiHeng
* @date: 2022/6/22 10:45
*/
@Component
@Slf4j
public class LockUtilImpl implements LockUtil {
/**
* 锁集合
*/
private final Map<String, Lock> lockMap = new ConcurrentHashMap<>();
/**
* 上锁
*
* @param key 上锁的key
* @param lockFunction 执行的函数
* @return 是否上锁成功
*/
@Override
public boolean lockAndExecute(String key, LockFunction lockFunction) {
// 获取锁
Lock lock = getLock(key);
// 上锁
lock.lock();
try {
// 执行业务
lockFunction.execute();
return true;
} catch (Exception e) {
log.error("lock service exception , exception is : ", e);
throw e;
} finally {
// 解锁
lock.unlock();
log.info("thread is unlock , start remove key");
// 移除锁信息
lockMap.remove(key);
}
}
/**
* 获取锁
*
* @param key key
* @return Lock
*/
private Lock getLock(String key) {
// 查询当前key是否存在锁
Lock lock = lockMap.get(key);
// 返回锁
return OptionalTactics
.of(Objects.nonNull(lock), Lock.class)
// 如果存在锁 直接返回
.whenTrue(() -> lock)
// 不存在创建一把锁添加到map中返回
.whenFalse(() -> {
// 加锁
synchronized (key) {
// 第二次取
Lock doubleCheckLock = lockMap.get(key);
// 第二次检查 不存在则创建
return OptionalTactics
.of(Objects.nonNull(doubleCheckLock), Lock.class)
// 如果第二检查的时候,有锁了则返回已经创建的锁
.whenTrue(() -> doubleCheckLock)
// 第二次检查如果没有锁的化 , 创建锁
.whenFalse(() -> {
// 创建新锁
Lock newLock = new ReentrantLock();
// 添加到集合中并且返回
return lockMap.put(key, newLock);
})
.execute();
}
})
.execute();
}
一个小的true或者false的策略模式
package com.zombies.pixel.common.utils;
import com.zombies.pixel.common.enums.BusinessResCode;
import com.zombies.pixel.common.exception.BusinessException;
import lombok.Data;
import java.util.Optional;
import java.util.function.Supplier;
/**
* @ClassName: OptionalTactics
* @Description: 一个简单的策略类
* @author: LeiHeng
* @date: 2022/6/17 15:41
*/
public class OptionalTactics<R> {
/**
* 规则
*/
private final Boolean rule;
/**
* true 所执行的函数
*/
private Supplier<R> trueFun;
/**
* false所执行的函数
*/
private Supplier<R> falseFun;
/**
* 返回值类型
*/
private final Class<R> resultType;
/**
* 构造器
*
* @param rule 规则
* @param resultType 返回值类型
*/
private OptionalTactics(boolean rule, Class<R> resultType) {
this.rule = rule;
this.resultType = resultType;
}
/**
* of 创建optionalTactics类
*
* @param rule 规则
* @param resultType 返回值类型
* @param <T> 泛型
* @return 返回optionalTactics类
*/
public static <T> OptionalTactics<T> of(boolean rule, Class<T> resultType) {
return new OptionalTactics<>(rule, resultType);
}
/**
* true所执行的函数
*
* @param trueFun 执行函数
* @return 返回optionalTactics类
*/
public OptionalTactics<R> whenTrue(Supplier<R> trueFun) {
this.trueFun = trueFun;
return this;
}
/**
* false所执行的函数
*
* @param falseFun 执行函数
* @return 返回optionalTactics类
*/
public OptionalTactics<R> whenFalse(Supplier<R> falseFun) {
this.falseFun = falseFun;
return this;
}
/**
* 执行
*
* @return 返回true或者false执行后的值
*/
public R execute() {
return rule ?
Optional
.ofNullable(trueFun)
.orElseThrow(() -> new RuntimeException( "true fun is null"))
.get()
:
Optional
.ofNullable(falseFun)
.orElseThrow(() -> new RuntimeException("false fun is null"))
.get();
}
}
欢迎大家讨论,并且指出不足!