在使用redis缓存时,为了避免因为缓存不存在的key,导致大量请求打到mysql时,需要对代码块加锁,只让一个线程进入mapper层,查询数据,然后放在缓存中即可package com.xtoshii.xcs.util;
import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; 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; /** * @program: xcs-boot2 * @description: * @author: xtoshii * @create: 2021-08-11 22:44 **/ @Slf4j @NoArgsConstructor public class KeyLocker<T> { private Map<T,Lock> lockMap = new ConcurrentHashMap<>(); public KeyLocker(int capacity){ this.lockMap = new ConcurrentHashMap<>(capacity); } public boolean tryLock(T t){ if(Objects.isNull(t)){ throw new NullPointerException(); } if(lockMap.containsKey(t)){ ReentrantLock lock = (ReentrantLock)lockMap.get(t); return lock.isHeldByCurrentThread();// 判断是否当前线程已持有锁,若持有,则返回true,否则为false } else { Lock lock = new ReentrantLock(); if(lock.tryLock()){ lockMap.put(t,lock); log.info("{} 获得资源 {}",Thread.currentThread().getName(),t); return true; } return false; } } public boolean tryRelease(T t){ if(Objects.nonNull(t) && lockMap.containsKey(t) ){ ReentrantLock lock = (ReentrantLock)lockMap.get(t);// 先判断是否锁是否有当前线程持有,持有方可解锁,否则会抛出 java.lang.IllegalMonitorStateException if(lock.isHeldByCurrentThread()){ lock.unlock(); lockMap.remove(t); log.info("{} 释放了锁 {}", Thread.currentThread().getName(), t); return true; } } return false; } }