单体服务通过业务字段加锁

44 阅读1分钟

在分布式时环境通过Redisson分布式锁,根据业务字段对一段逻辑进行加锁,本代码是作为一个单体项目实现类似效果。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockByKey {

    private static final Logger log = LoggerFactory.getLogger(ReentrantLockByKey.class);

    private final Map<String, ReentrantLock> mutexCache = new ConcurrentHashMap<>();

    /**
     * 根据业务字段值对执行的内容进行加锁,获取锁失败则直接返回,代表该任务已经在运行
     * @param key 加锁的业务字段值
     * @param statement 加锁的执行逻辑
     */
    public void exec(String key,Runnable statement){
        ReentrantLock mutex4key = null;
        ReentrantLock mutexInCache;
        do{
            if(mutex4key != null){
                mutex4key.unlock();
            }
            mutex4key = mutexCache.computeIfAbsent(key,k->new ReentrantLock());
            boolean tryLock = mutex4key.tryLock();
            if(tryLock){
                mutexInCache = mutexCache.get(key);
            }else {
                log.info("key[{}],任务已执行",key);
                return;
            }
        }while (mutexInCache == null || mutex4key != mutexInCache);

        try{
            statement.run();
        }catch (Exception e){
            log.error("任务执行出现异常key:{},错误信息:{}",key,e.getMessage(),e);
            throw e;
        }finally {
            if(mutex4key.getQueueLength() == 0){
                mutexCache.remove(key);
            }
            mutex4key.unlock();
        }
    }
}