美文网首页JAVA
利用Redis实现无阻塞式锁

利用Redis实现无阻塞式锁

作者: 大华夏 | 来源:发表于2019-01-10 18:09 被阅读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  实际项目中的业务逻辑
                }
            });
    

    相关文章

      网友评论

        本文标题:利用Redis实现无阻塞式锁

        本文链接:https://www.haomeiwen.com/subject/fhnarqtx.html