• redis分布式锁


    package com.campuscard.core.utils;
    
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    
    import org.apache.commons.lang3.StringUtils;
    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.data.redis.serializer.RedisSerializer;
    
    public class RedisLock {
        // 加锁超时时间,单位毫秒, 即:加锁时间内执行完操作,如果未完成会有并发现象
        private static final long LOCK_TIMEOUT = 3 * 1000;
    
        private StringRedisTemplate stringRedisTemplate;
    
        public RedisLock(StringRedisTemplate stringRedisTemplate) {
            this.stringRedisTemplate = stringRedisTemplate;
        }
    
        /**
         * 加锁 取到锁加锁,取不到锁一直等待知道获得锁
         * 
         * @param lockKey
         * @param threadName
         * @return
         */
        public synchronized long lock(String lockKey) {
            while (true) { // 循环获取锁
                // 锁时间
                Long lock_timeout = currtTimeForRedis() + LOCK_TIMEOUT + 1;
                if (stringRedisTemplate.execute(new RedisCallback<Boolean>() {
                    @Override
                    public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
                        // 定义序列化方式
                        RedisSerializer<String> serializer = stringRedisTemplate.getStringSerializer();
                        byte[] value = serializer.serialize(lock_timeout.toString());
                        boolean flag = redisConnection.setNX(lockKey.getBytes(), value);
                        return flag;
                    }
                })) {
                    // 如果加锁成功
                    // 设置超时时间,释放内存
                    stringRedisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
                    return lock_timeout;
                } else {
                    // 获取redis里面的时间
                    String result = stringRedisTemplate.opsForValue().get(lockKey);
                    Long currt_lock_timeout_str = result == null ? null : Long.parseLong(result);
                    long time = new Date().getTime();
                    // 锁已经失效
                    if (currt_lock_timeout_str != null && currt_lock_timeout_str < time) {
                        // 判断是否为空,不为空时,说明已经失效,如果被其他线程设置了值,则第二个条件判断无法执行
                        // 获取上一个锁到期时间,并设置现在的锁到期时间
                        String str = stringRedisTemplate.opsForValue().getAndSet(lockKey, lock_timeout.toString());
                        if(StringUtils.isNotBlank(str)) {
                            Long old_lock_timeout_Str = Long.parseLong(str);
                            if (old_lock_timeout_Str != null && old_lock_timeout_Str.equals(currt_lock_timeout_str)) {
                                // 多线程运行时,多个线程签好都到了这里,但只有一个线程的设置值和当前值相同,它才有权利获取锁
                                // 设置超时间,释放内存
                                stringRedisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS);    
                                // 返回加锁时间
                                return lock_timeout;
                            }
                        }
                    }
                }
    
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        /**
         * 解锁
         * 
         * @param lockKey
         * @param lockValue
         * @param threadName
         */
        public synchronized void unlock(String lockKey, long lockValue) {
            // 获取redis中设置的时间
            String result = stringRedisTemplate.opsForValue().get(lockKey);
            Long currt_lock_timeout_str = result == null ? null : Long.parseLong(result);
    
            // 如果是加锁者,则删除锁, 如果不是,则等待自动过期,重新竞争加锁
            if (currt_lock_timeout_str != null && currt_lock_timeout_str == lockValue) {
                stringRedisTemplate.delete(lockKey);
            }
        }
    
        /**
         * 多服务器集群,使用下面的方法,代替System.currentTimeMillis(),获取redis时间,避免多服务的时间不一致问题!!!
         * 
         * @return
         */
        public long currtTimeForRedis() {
            return stringRedisTemplate.execute(new RedisCallback<Long>() {
                @Override
                public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
                    return redisConnection.time();
                }
            });
        }
    }
  • 相关阅读:
    ls: cannot open directory .: Permission denied
    postman报错:Could not get any response
    IO流的继承关系
    吸顶效果
    linux报错:ls command not found
    内存寻址能力与CPU的位宽有关系吗?
    CPU与内存
    SQL语言的分类
    32位CPU和64位CPU 区别
    linux添加环境变量
  • 原文地址:https://www.cnblogs.com/feiyun126/p/8573215.html
Copyright © 2020-2023  润新知