JAVA

利用Redis实现无阻塞式锁

2019-01-10  本文已影响17人  大华夏

锁要达到的效果

在实际的业务逻辑中,不需要去考虑能不能获取到锁

A线程在使用锁(锁尚未被A线程释放),而B线程执行了获取锁,这时B线程有两种处理:
①、未能获取到锁,逻辑退出;
②、利用循环逻辑不停的获取锁,直到得到锁,继续后面的逻辑

实际的业务逻辑中,不需要考虑锁的释放问题

只需要要执行获取锁就可以了,锁自动释放

锁封装处理

①.Redis操作封装类

/**
 * Redis访问封装
 * @author chester
 *
 */
@Component
public class RedisService {

    @Autowired
    private JedisPool jedisPool;

    public JedisPool getJedisPool() {
        return jedisPool;
    }
    public <T> T callJedis(ICallJedis<T> icallJedis) {
        final Jedis jedis = jedisPool.getResource();
        try {
            return icallJedis.call(jedis);
        }catch (Exception e) {
            LogUtil.error(ExceptionUtils.getStackFrames(e));
            
        } finally {
            jedis.close();
        }
        throw new RuntimeException("请求Redis出错!!!"); 
    }

    public static interface ICallJedis<T> {
        public T call(Jedis jedis);
    }
            /**
     * Redis Incr 命令将 key 中储存的数字值增一。
     * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
     * @param key
     * @return
     */
    public Long incr(String key) {
        return callJedis(new ICallJedis<Long>() {

            @Override
            public Long call(Jedis jedis) {
                return jedis.incr(key);
            }
        });
    }
    
      public Long pexpire(String key,long milliseconds) {
        return callJedis(new ICallJedis<Long>() {

            @Override
            public Long call(Jedis jedis) {
                
                return jedis.pexpire(key, milliseconds);
            }
        });
    }
        //TODO  其他操作封装未贴出
}

②.Redis锁封装

/**
 * 用Redis封装的锁,用于修改数据
 * @author chester
 *
 */
public class RedisLock {
    //taskExecutor 可根据实际情况,利用项目中的线程
    private static ExecutorService taskExecutor = Executors.newFixedThreadPool(4); 
    //锁的Key
    private String lockKey;
    //锁过期时间
    private int expireTime;
    //redis客户端
    private RedisService redisService;
    
    //业务逻辑在此接口中执行
    public static interface IProcesser{
        public void process() throws Exception;
    }
    public RedisLock(RedisService redisService,long rid,String category) {
        this(redisService, rid, category, 2000);
    }
    public RedisLock(RedisService redisService,long rid,String category,int milliseconds) {
        this.lockKey = "RedisLock_"+rid+"_"+category;
        this.redisService = redisService;
        this.expireTime = milliseconds;
    }
    /**
     * 获取锁
     * @return
     */
    public boolean get() {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        taskExecutor.execute(new Worker(countDownLatch));
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }
    
    public void release() {
        redisService.del(lockKey);
    }
    /**
     * 利用此函数执行业务逻辑
     * @param iProcesser
     * @throws Exception
     */
    public void process(IProcesser iProcesser) throws Exception{
        if(get()) {
            try {
                iProcesser.process();
            } finally {
                release();
            }
        }
    }
    //保证获取到锁
    private class Worker implements Runnable{
        private CountDownLatch countDownLatch;
        Worker(CountDownLatch countDownLatch){
            this.countDownLatch = countDownLatch;
        }

        public void run() {
            while (true) {
                boolean ok = (redisService.incr(lockKey) == 1);
                if(ok) {
                    redisService.pexpire(lockKey, (long)expireTime);
                    countDownLatch.countDown();
                    break;
                }
                try {
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        }
    }
}

项目使用

//针对rid创建不同类型的锁
new RedisLock(redisService, rid, RedisLockCategory).process(new RedisLock.IProcesser() {
            
            @Override
            public void process() throws LangException {
                //TODO  实际项目中的业务逻辑
            }
        });
上一篇下一篇

猜你喜欢

热点阅读