单台tomcat上利用锁解决redis缓存击穿

1 可重入锁 ReentrantLock类

在解决缓存击穿时,使用了锁,在springboot项目中,直接基于java.util.concurrent.locks(JUC)获取可重入锁——ReentrantLock类

image

2 单台tomcat上利用锁解决缓存击穿

    技术点:

    1. try-catch-finally的finally下释放锁,而不能放在try下,要避免代码出错时导致代码运行不到释放锁的那行,导致锁无法释放

    2. 加锁后,就要让其他没有获取到锁的进程睡眠等待一段时间,过段时间再请求获取锁,这个过程叫自旋

    3. 使用log对象输出信息而不使用system.out.print,是因为后者影响性能

    4. 要给锁加过期时间,避免代码执行到一半服务器断电,导致代码只执行一半,最后锁没能得到释放

public class UserServiceImpl implements UserService {
    //声明log日志对象 相比system.out.pringt 更节省系统资源
    Log log = LogFactory.getLog(UserServiceImpl.class);
    //获取重复锁
    private ReentrantLock lock = new ReentrantLock();
    //获取操作redis的类
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    
    @Override
    public UserInfo getUser(Integer id) {
        UserInfo userInfo = null;
        String key = RedisConstants.USER_INFO_KEY + id;
        String s = stringRedisTemplate.opsForValue().get(key); //查询redis缓存
        if(s == null){ //redis缓存中不存在
            try {
                Thread.sleep(5000);
                if(lock.tryLock()){  //通过ReentrantLock对象上锁
                    try {
                        //查询数据库,将数据库查询的对象保存至缓存中
                        log.info("查询了数据库");
                        userInfo = new UserInfo(id, "admin", "admin"); // 查询出的对象
                        String userInfoStr = JSON.toJSONString(userInfo);
                        stringRedisTemplate.opsForValue().set(key,userInfoStr,30,TimeUnit.DAYS);
                    } finally {
                        lock.unlock(); //释放锁
                    }
                }else{ //锁被占用,没能获取到锁的线程
                    Thread.sleep(1000); //睡眠等待1秒钟
                      getUser(id);//递归,继续尝试获取锁并查询redis缓存
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{ //缓存命中
            userInfo = JSON.parseObject(s, UserInfo.class);//从redis中取出数据
            log.info("命中了缓存");
        }
        // 查询数据库
        return userInfo;
    }
}
posted @ 2021-10-10 22:32  夏·舍  阅读(59)  评论(0编辑  收藏  举报