• 基于Redis实现分布式锁


    分布式锁是控制分布式系统之间同步访问共享资源的一种方式

    锁接口定义

    定义一个锁通用接口,对外提供锁服务

    import java.util.concurrent.TimeUnit;
    
    public interface LockService {
        /** 
         * 尝试获取锁
         * @param 锁名
         */
    	public boolean tryLock(String name);
        /** 
         * 在指定时间内尝试获取锁
         * @param 锁名
         * @param 尝试时间
         */
    	public boolean tryLock(String name, long timeout, TimeUnit unit);
        /** 
         * 获取锁,阻塞方法,直到获取锁成功为止
         * @param 锁名
         */
    	public void lock(String name) throws Exception;
        /** 
         * 释放锁
         * @param 锁名
         */
    	public void unlock(String name);
    
    }
    

    redis锁的实现:

    public class RedisLockService implements LockService {
    
        private static final String NAMESPACE = "lock-service:";
        private static final Logger log = LogManager.getLogger(RedisLockService.class);
    
        @Autowired
        private RedisTemplate<String, String> stringRedisTemplate;
    
        /** 锁默认超时时间,单位:秒 */
        @Value("${lockService.timeout:300}")
        private int timeout;      
    
        /** 服务ID,用于区分释放锁权限。 */
        @Value("${instance.id:locks}")
        private String instanceId;
    
    
        @Override
        public boolean tryLock(String name) {
            String key = NAMESPACE + name;
            String value = getValue();
            boolean success = stringRedisTemplate.opsForValue().setIfAbsent(key, value);    //如果不存在key,则set
            if (success)
                stringRedisTemplate.expire(key, this.timeout, TimeUnit.SECONDS);            //设置默认锁有效时间
            return success;
        }
    
        @Override
        public boolean tryLock(String name, long timeout, TimeUnit unit) {
            if (timeout <= 0)
                return tryLock(name);
            String key = NAMESPACE + name;
            String value = getValue();
            boolean success = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
            long millisTimeout = unit.toMillis(timeout);
            long start = System.currentTimeMillis();
            while (!success) {          //若获取锁不成功,则在限定时间内不断尝试,直到获取成功,或超时
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    return false;
                }
                if ((System.currentTimeMillis() - start) >= millisTimeout)
                    break;
                success = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
            }
            if (success)
                stringRedisTemplate.expire(key, this.timeout, TimeUnit.SECONDS);
            return success;
        }
    
        @Override
        public void lock(String name) {
            String key = NAMESPACE + name;
            String value = getValue();
            boolean success = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
            while (!success) {
                try {
                    Thread.sleep(100);          //每间隔100毫秒,再次尝试获取锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                success = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
                if (success)
                    stringRedisTemplate.expire(key, this.timeout, TimeUnit.SECONDS);
            }
    
        }
    
        @Override
        public void unlock(String name) {
            String key = NAMESPACE + name;
            String value = getValue();
            //一行lua脚本,如果KEY的值等于VALUE,则删除KEY,否则返回0
            String str = "if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end";
            RedisScript<Long> script = new DefaultRedisScript<Long>(str, Long.class);
            Long ret = stringRedisTemplate.execute(script, Collections.singletonList(key), value);
            if (ret == 0)
                log.warn("Lock [{}] is not hold by instance [{}]", name, value);
        }
    
        /**
         * 生成由服务ID+线程名组成的线程唯一value。用于保证只能被拥有锁的线程解锁
         */
        private String getValue(){
            return instanceId + Thread.currentThread().getName();
        }
    
    }
    
    
  • 相关阅读:
    DevExpress.XtraCharts.chartControl
    DevExpress控件之:ChartControl 动态绑定数据
    字符串的方法详解
    编码
    格式化输出
    关于while循环中的break和continue的区别
    while循环和for循环
    [AGC028D] Chords
    [CF1392H] ZS Shuffles Cards
    [CF568E] Longest Increasing Subsequence
  • 原文地址:https://www.cnblogs.com/coderzl/p/7490226.html
Copyright © 2020-2023  润新知