zoukankan      html  css  js  c++  java
  • redis分布式锁实现

    public interface DistributedLock {
        /**
         * 加锁
         * @param lockKey 锁定的key
         * @param lockSeconds  锁定时间(单位:秒),超过该锁定时间会自动释放锁,可能会导致并发问题。
         * @param expirySeconds  本次获取锁请求失效时间(单位:秒)
         * @param sleepMillisecond 本次获取锁失败,等到多少毫秒再次尝试获取(单位:毫秒)
         * @return 返回值大于0,则说明获取到锁,调用者需要保留该值,并在解锁时传入。
         */
        public Long lock(String lockKey,long lockSeconds, long expirySeconds, int sleepMillisecond);
        
        /**
         * 解锁
         * @param lockKey 锁定的key
         */
        public void unlock(String lockKey,long lockValue);
    }
    import java.util.concurrent.TimeUnit;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.dao.DataAccessException;
    import org.springframework.data.redis.connection.RedisConnection;
    import org.springframework.data.redis.core.RedisCallback;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Service;
    
    import com.aaron.redis.lock.DistributedLock;
    
    @Service("redisDistributedLock")
    public class RedisDistributedLockImpl implements DistributedLock {
        private static final Logger LOG = LoggerFactory.getLogger(RedisDistributedLockImpl.class);
    
        /**
         * 锁定超时时间60秒, 单位毫秒, 意味着加锁期间内执行完操作 如果未完成会自动过期释放锁,造成并发问题。
         */
        private static final long DEFAULT_LOCK_TIMEOUT = 60 * 1000;
    
        @Autowired
        protected StringRedisTemplate stringRedisTemplate;
    
        @Override
        public Long lock(String lockKey, long lockSeconds, long expirySeconds, int sleepMillisecond) {
            Long lockVal = 0L;
            long currMs = System.currentTimeMillis();
            if (lockSeconds > 0L) {
                lockSeconds = lockSeconds * 1000;
            } else {
                lockSeconds = DEFAULT_LOCK_TIMEOUT;
            }
            while (true) {
                Long nextmin = getNextMin();
    
                boolean lockResult = stringRedisTemplate.execute(new RedisCallback<Boolean>() {
                    @Override
                    public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                        return connection.setNX(lockKey.getBytes(), String.valueOf(nextmin).getBytes());
                    }
                });
                if (lockResult) {// 获得锁
                    LOG.debug("+++key:{} lock success", lockKey);
                    stringRedisTemplate.expire(lockKey, lockSeconds, TimeUnit.MILLISECONDS); // 设置超时时间,释放内存
                    lockVal = nextmin;
                    break;
                } else {
                    // 调用get
                    String lockTimeObj = stringRedisTemplate.opsForValue().get(lockKey); // redis里的时间
    
                    if (null != lockTimeObj) {
                        Long ts = Long.valueOf(lockTimeObj);
                        long nowTs = System.currentTimeMillis();
                        if (nowTs - ts >= 0) {// 锁已经失效
                            // 调用getset,获取旧值,写入新值,获取不到值为null
                            long nextminVal = getNextMin();
                            String lockTimeObj1 = stringRedisTemplate.opsForValue().getAndSet(lockKey,
                                    String.valueOf(nextminVal));
                            if (null == lockTimeObj1 || lockTimeObj.equals(lockTimeObj1)) {
                                stringRedisTemplate.expire(lockKey, lockSeconds, TimeUnit.MILLISECONDS); // 设置超时时间,释放内存
                                lockVal = nextminVal;
                                break;
                            }
                        }
                    }
    
                    if (lockVal == 0L) {
                        if (checkTimeout(currMs, expirySeconds)) {
                            break;
                        }
                        sleep(sleepMillisecond);
                    }
                }
            }
            return lockVal;
        }
    
        @Override
        public void unlock(String lockKey, long lockValue) {
            if (lockValue <= 0L) {
                return;
            }
            String objVal = stringRedisTemplate.opsForValue().get(lockKey);
            if (objVal != null && objVal.equals(String.valueOf(lockValue))) {
                stringRedisTemplate.delete(lockKey); // 删除键
                LOG.debug("+++key:{} release success", lockKey);
            }
        }
    
        private boolean checkTimeout(long currMs, long expirySeconds) {
            return (System.currentTimeMillis() - currMs) > (expirySeconds * 1000);
        }
    
        private long getNextMin() {
            return System.currentTimeMillis() + 60000;
        }
    
        private void sleep(int ms) {
            try {
                if (ms <= 0) {
                    ms = 50;
                }
                Thread.sleep(ms);
            } catch (InterruptedException e) {
            }
        }
    
    }

            //lockKey
            String lockKey = "lockKey"; //key
            //获取到锁,则锁定30秒
            long lockSeconds = 30;
            //请求200秒如果还没获取到锁就超时返回
            long expirySeconds = 0;
            //未获取到锁,则休息30毫秒然后重试,直到expirySeconds过期
            int sleepMillisecond = 30;
            //获取锁
            long lockVal = redisDistributedLock.lock(lockKey, lockSeconds, expirySeconds, sleepMillisecond);
            //获取锁成功
            if(lockVal > 0L){
                try{
              //执行逻辑
           }catch (Exception e){
    }
    finally{ //释放锁 redisDistributedLock.unlock(lockKey, lockVal); } }else{ //获取锁失败 } }
  • 相关阅读:
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I作业12
    C语言I博客作业11
    C语言I博客作业10
    C语言I博客作业09
    C语言I作业08
    C语言ㅍ作业01 结构:通讯录
    C语言寒假大作战04
    C语言寒假大作战03
  • 原文地址:https://www.cnblogs.com/aaronzheng/p/12106064.html
Copyright © 2011-2022 走看看