码迷,mamicode.com
首页 > 其他好文 > 详细

redisLock

时间:2019-12-27 11:34:05      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:finally   dex   call   callback   red   get   service   ogg   单位   

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.msxf.boot.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{ //获取锁失败 } }

redisLock

标签:finally   dex   call   callback   red   get   service   ogg   单位   

原文地址:https://www.cnblogs.com/aaronzheng/p/12106064.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!