redis之双重检查锁(double check lock)的使用

转 https://blog.csdn.net/qq_18800463/article/details/79548175

通常使用redis的使用如下:

public List<Order> query(){
    //1.查询缓存
    ValueOperations ops = redisTemplate.opsForValue();
    String json = String.valueOf(ops.get(CACHE_KEY));
    //2.判断缓存中是否有数据
    if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){
        //返回缓存数据
        logger.info("----query for cache----------");
        return JSON.parseArray(json,Order.class);
    }
    //3.查看数据库,并且返回数据,同时更新缓存
    List<Order> list = orderMapper.getAll();
    ops.set(CACHE_KEY,JSON.toJSON(list),10, TimeUnit.MINUTES);
    return  list;
}
 

当使用多线程 CountDownLatch测试时,会造成缓存击穿

代码如下:

public class CacheTest2 {
    private static final Logger logger = LoggerFactory.getLogger(CacheTest2.class);

    private static final int THREAD_NUM = 10;
    //倒计时器
    private CountDownLatch cdl = new CountDownLatch(THREAD_NUM);

    @Autowired
    private CacheService cacheService;

    public void testCache2() throws Exception{
        for (int i = 0; i < THREAD_NUM; i++) {
            new Thread(new QueryTask()).start();
            cdl.countDown();
        }
        //主线程休眠 也可以考虑用join
        Thread.currentThread().sleep(5000);
        //结果:并发导致缓存失效,使用策略 double check lock (SpringCache)
    }
    private class QueryTask implements Runnable{
        @Override
        public void run() {
            try {
                cdl.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            List<Order> list = cacheService.query();
            logger.info(list.toString());
        }
    }
}

使用双重检查锁:

public /*synchronized */List<Order> query(){
    //1.查询缓存
    ValueOperations ops = redisTemplate.opsForValue();
    String json = String.valueOf(ops.get(CACHE_KEY));
    //2.判断缓存中是否有数据
    if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){
        //返回缓存数据
        logger.info("----query for cache----------");
        return JSON.parseArray(json,Order.class);
    }
    //Spring Cache
    //double check lock
    synchronized (this){
        json = String.valueOf(ops.get(CACHE_KEY));
        if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){
            //返回缓存数据
            logger.info("----query for cache----------");
            return JSON.parseArray(json,Order.class);
        }
        //3.查看数据库,并且返回数据,同时更新缓存
        List<Order> list = orderMapper.getAll();
        ops.set(CACHE_KEY,JSON.toJSON(list),10, TimeUnit.MINUTES);
        return  list;
    }
}

封装成redis缓存查询模板

1.查询接口

public interface CacheLoadable<T> {
    public T load();
}

2.查询Service

public List<Order> queryByTemplate(){
    return cacheTemplateService.findCache(CACHE_KEY, 10, TimeUnit.MINUTES,
            new TypeReference<List<Order>>() {
            }, new CacheLoadable<List<Order>>() {
                @Override
                public List<Order> load() {
                    return orderMapper.getAll();
                }
            });
}

3.封装成模板

@Component
public class CacheTemplateService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderMapper orderMapper;

    public static final Logger logger = LoggerFactory.getLogger(CacheTemplateService.class);

    public <T> T findCache(String key, long expire, TimeUnit timeUnit,
                           TypeReference<T> clazz, CacheLoadable<T> cacheLoadable){
        ValueOperations ops = redisTemplate.opsForValue();
        String json = String.valueOf(ops.get(key));
        if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){
            //返回缓存数据
            logger.info("----query for cache----------");
            return JSON.parseObject(json,clazz);
        }
        synchronized (this){
            json = String.valueOf(ops.get(key));
            if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){
                logger.info("----query for cache----------");
                return JSON.parseObject(json,clazz);
            }
            //核心业务
            T result = cacheLoadable.load();
            //2-3s
            ops.set(key,JSON.toJSON(result),expire, timeUnit);
            return  result;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/banqgg/article/details/82584781
今日推荐