Redis分布式锁 根据 redisTemplate创建

第一种

原文地址

https://www.jb51.net/article/147617.htm

***
 * 第一种Redis 分布式锁
 */
class CommonRedisHelper {
    public static final String LOCK_PREFIX = "redis_lock";
    public static final int LOCK_EXPIRE = 300; // ms
    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 最终加强分布式锁
     *
     * @param key key值
     * @return 是否获取到
     */
    public boolean lock(String key) {
        String lock = LOCK_PREFIX + key;
        // 利用lambda表达式
        return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
            long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
            Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
            if (acquire) {
                return true;
            } else {
                byte[] value = connection.get(lock.getBytes());
                if (Objects.nonNull(value) && value.length > 0) {
                    long expireTime = Long.parseLong(new String(value));
                    if (expireTime < System.currentTimeMillis()) {
                        // 如果锁已经过期
                        byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
                        // 防止死锁
                        return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
                    }
                }
            }
            return false;
        });
    }

    /**
     * 删除锁
     *
     * @param key
     */
    public void delete(String key) {
        redisTemplate.delete(key);
    }

// 测试
    public static void main(String[] args) {
        String key = "1";
        CommonRedisHelper redisHelper = new CommonRedisHelper();
        boolean lock = redisHelper.lock(key);
        if (lock) {
            // 执行逻辑操作
            redisHelper.delete(key);
        } else {
            // 设置失败次数计数器, 当到达5次时, 返回失败
            int failCount = 1;
            while (failCount <= 5) {
                // 等待100ms重试
                try {
                    Thread.sleep(100L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (redisHelper.lock(key)) {
                    // 执行逻辑操作
                    redisHelper.delete(key);
                } else {
                    failCount++;
                }
            }
            throw new RuntimeException("现在创建的人太多了, 请稍等再试");
        }
    }
}

/***
 *
 *
 * 注意事项:
 *
 * 1、获取锁时设置key的value值需要保持一定的唯一性,以识别是否是加锁和解锁的线程
 *
 * 2、key对应设置生命周期expireTime,防止死锁
 *
 */

第二种

原文地址

https://blog.csdn.net/weixin_43952575/article/details/123000060

/**
 * 设置等待时间,在时间内 循环操作   第二种
 */
@Component
class RedisLockUtilWithWaittime {

    @Autowired
    private RedisTemplate redisTemplate;

    public static final String LOCKED = "TRUE";
    public static final long EXPIRE = 120L;
    public static final long ONE_MILLI_NANOS = 1000000L;
    public static final long DEFAULT_TIME_OUT = 2000L;
    public static final Random RANDOM = new Random();

    public RedisLockUtilWithWaittime() {

    }

    // 函数式接口
    public interface MainOperator<T> {
        boolean HOLD_LOCK_TAG = false;

        T executeInvokeLogic(boolean result) throws Exception;
    }

    // 等待时间重复获取
    public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey, long milliTimeout) throws Exception {
        try {
            if (operator != null && lockCacheKey != null && milliTimeout >= 0L) {
                boolean locked = false;
                long startNano = System.nanoTime();
                boolean waitFlag = milliTimeout > 0L;
                long nanoTimeOut = (waitFlag ? milliTimeout : 50L) * 1000000L;
                T resultObj = null;

                try {
                    while (System.nanoTime() - startNano < nanoTimeOut) {
                        if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.SECONDS)) {
                            locked = true;
                            break;
                        }

                        if (!waitFlag) {
                            break;
                        }

                        Thread.sleep(30L, RANDOM.nextInt(500));
                    }

                    resultObj = operator.executeInvokeLogic(locked);
                } catch (Exception ex) {
                    throw ex;
                } finally {
                    if (locked) {
                        releaseRedisLock(lockCacheKey);
                    }

                }
                return resultObj;
            } else {
                throw new Exception("参数不合法");
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * @deprecated
     */
    // 不推荐使用
    @Deprecated
    public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey) throws Exception {
        boolean locked = false;
        T resultObj = null;

        try {
            if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.MICROSECONDS)) {
                locked = true;
            }

            resultObj = operator.executeInvokeLogic(locked);
        } catch (Exception ex) {
            throw ex;
        } finally {
            if (locked) {
                releaseRedisLock(lockCacheKey);
            }

        }

        return resultObj;
    }


    /**
     * 释放锁
     *
     * @param cacheKey
     */
    public boolean releaseRedisLock(final String cacheKey) {
        Boolean deleteLock = redisTemplate.delete(cacheKey);
        if (Boolean.TRUE.equals(deleteLock)) {
            return true;
        }
        return false;
    }


    public static void main(String[] args) {
        /***
         * 使用测试
         */
        /**
         * 在时间范围内重复执行操作,直到成功
         * @return
         * @throws Exception
         */
        RedisLockUtilWithWaittime redisLockUtilWithWaittime = new RedisLockUtilWithWaittime();
        String localKey = "myTest_1";
        try {

            String s = redisLockUtilWithWaittime.executeSynchOperate(result -> {
                if (!result) {
                    throw new Exception("");
                }
                // 数据库逻辑
                return "ww";
            }, localKey, 5000);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

第三种

原文地址

https://blog.csdn.net/long2010110/article/details/82911168?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-2-82911168-blog-123393216.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-2-82911168-blog-123393216.pc_relevant_default&utm_relevant_index=5


/**
 * 第三种
 */
class RedisLock {
    @Autowired
    static RedisTemplate redisTemplate;

    private static final Long SUCCESS = 1L;

    /**
     * 获取锁
     *
     * @param lockKey
     * @param value
     * @param expireTime:单位-秒
     * @return
     */
    public static boolean getLock(String lockKey, String value, int expireTime) {
        boolean ret = false;
        try {
            String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";

            RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);

            Long result = (Long) redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value, expireTime);

            if (SUCCESS.equals(result)) {
                return true;
            }

        } catch (Exception e) {

        }
        return ret;
    }

    /**
     * 释放锁
     *
     * @param lockKey
     * @param value
     * @return
     */
    public static boolean releaseLock(String lockKey, String value) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);

        Long result = (Long) redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value);
        if (SUCCESS.equals(result)) {
            return true;
        }

        return false;
    }
}

第四种

原文地址

https://blog.csdn.net/jf991804033/article/details/109382683?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165474058716780357210246%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=165474058716780357210246&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogbaidu_landing_v2~default-1-109382683-null-null.nonecase&utm_term=redistemplate+%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&spm=1018.2226.3001.4450

class RedisLockUtils {


    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取锁的超时时间
     */
    private static final long timeout = 300;

    /**
     * 加锁,无阻塞
     *
     * @param key
     * @param expireTime
     * @param value      存入Redis 值   推荐使用 uuid
     * @return
     */
    public Boolean lock(String key, String value, long expireTime) {

        String requestId = value;
        Long start = System.currentTimeMillis();
        //自旋,在一定时间内获取锁,超时则返回错误
        for (; ; ) {
            //Set命令返回OK,则证明获取锁成功
            Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, requestId, expireTime,
                    TimeUnit.SECONDS);
            if (ret) {
                return true;
            }
            //否则循环等待,在timeout时间内仍未获取到锁,则获取失败
            long end = System.currentTimeMillis() - start;
            if (end >= timeout) {
                return false;
            }
        }
    }


    /**
     * 删除缓存
     * *
     *
     * @param key 可以传一个值 或多个      建议与lun脚本一起使用
     */
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    public static void main(String[] args) {
        /**
         * 锁的key前缀
         */
        String lockStr = "r_lock_";

         /**
         * 获取锁最大失败次数
         */
        int maxFailCount = 5;
        RedisLockUtils  redisLockUtils =new RedisLockUtils();

        String key = "test";
        // 锁的过期时间,避免死锁,根据业务调整,毫秒
        long expireTime = 1000;
        //判断是否获得锁
        boolean lock = redisLockUtils.lock(lockStr,UUID.randomUUID().toString(),  expireTime);
        if (lock) {
            try {


                //处理业务的方法
                //TODO


            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //解锁
                redisLockUtils .del(lockStr);
            }
        } else {
            int failCount = 1;
            while (failCount <= maxFailCount) {
                //判断是否获得锁
                if ( redisLockUtils.lock(lockStr,UUID.randomUUID().toString(),  expireTime) ){
                    //处理业务的方法
                    //TODO

                    //解锁
                    redisLockUtils .del(lockStr);
                } else {
                    failCount++;
                }
            }
            throw new RuntimeException("当前创建的数量太多了,请稍后再试。");
        }
    }

}

第五种

原文地址

https://blog.csdn.net/lzq199528/article/details/103421826?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165474165516780366537860%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165474165516780366537860&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-10-103421826-null-null.nonecase&utm_term=redistemplate+%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&spm=1018.2226.3001.4450

class RedisImpl {
    @Autowired
    public RedisTemplate redisTemplate;

//    @Scheduled(cron = "* * * * * ?")
//    public void test() {
//        // 模仿多服务
//        System.out.println("======================================================");
//        new Thread(() -> redisLock("线程1")).start();
//        new Thread(() -> redisLock("线程2")).start();
//        new Thread(() -> redisLock("线程3")).start();
//        new Thread(() -> redisLock("线程4")).start();
//    }


    public void redisLock(String threadName) {
        boolean bol = getLock("aa");
        if (bol) {
            try {
                // 执行业务
                System.out.println(threadName + "执行业务");
            } finally {
                unlock("aa");
            }

        } else {
            // 并发执行了
            System.out.println("有服务器正在执行此次无需再次执行");
        }

    }



    // 获得锁 ture 获得锁 false 没有获得锁
    public Boolean getLock(String key) {
        // 创建事物 防止命令执行一半
        redisTemplate.multi();
        redisTemplate.execute(
                (RedisCallback<Boolean>) conn -> {
                    try {
                        conn.setNX(redisTemplate.getStringSerializer().serialize(key),
                                redisTemplate.getStringSerializer().serialize(key));
                    } finally {
                        // 关闭释放链接
                        conn.close();
                    }
                    return null;
                });
        // 防止死锁。 10秒后删除key
        redisTemplate.expire(key, 10, TimeUnit.SECONDS);
        List<Object> list = redisTemplate.exec();
        return (Boolean) list.get(0);
    }

    // 释放锁
    private void unlock(String key) {
        redisTemplate.delete(key);
    }
}

第六种

原文地址

https://blog.csdn.net/qq_34560135/article/details/113556357?ops_request_misc=&request_id=&biz_id=102&utm_term=redistemplate%20%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&utm_medium=distribute.pc_search_result.none-task-blog-2blogsobaiduweb~default-2-113556357.nonecase&spm=1018.2226.3001.4450

class RedisLockUtil {


    private static ThreadLocal<Thread> THREA_LOCAL = new ThreadLocal<>();
    private final String lock_prefix = "lock_prefix:";
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**  加锁
     * @param lock   锁 的key
     * @param timeoutSeconds
     * @return
     * @throws InterruptedException
     */
    public String lock(String lock, long timeoutSeconds) throws InterruptedException {

        try {
            String identification = UUID.randomUUID().toString();
            String lockName = String.format("%s%s", lock_prefix, lock);

            Boolean flag = redisTemplate.opsForValue().setIfAbsent(lockName, identification, timeoutSeconds, TimeUnit.SECONDS);
            if (flag) {
                // 续签
                Thread renewal = new Thread(new RenewalLock(lock, identification, timeoutSeconds));
                renewal.setDaemon(true);
                THREA_LOCAL.set(renewal);
                renewal.start();
                return identification;
            }
        } finally {
            //  加锁失败处理

        }

        return "";
    }

    /** 释放锁
     * @param lock
     * @param identification
     */
    public void release(String lock, String identification) {
        try {
            redisTemplate.setEnableTransactionSupport(true);
            String lockName = String.format("%s%s", lock_prefix, lock);
            redisTemplate.watch(lockName);
            String identificationDB = redisTemplate.opsForValue().get(lockName);
            if (identificationDB != null && identification != null && identification.equals(identificationDB)) {
                redisTemplate.multi();
                redisTemplate.delete(lockName);
                redisTemplate.exec();
            }
            redisTemplate.unwatch();
        } finally {
            RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
            THREA_LOCAL.get().interrupt();
            THREA_LOCAL.remove();
        }
    }

    /**
     * 续签lock
     */
    private class RenewalLock implements Runnable {

        private String lockName;
        private String identification;
        private Long timeout;

        public RenewalLock(String lock, String identification, Long timeout) {
            this.lockName = lock_prefix + lock;
            this.identification = identification;
            this.timeout = timeout;
        }

        @Override
        public void run() {
            int i = 0;
            while (true) {
                try {
                    if (Thread.currentThread().isInterrupted()) {
                        return;
                    }
                    TimeUnit.SECONDS.sleep(timeout / 2);
                    redisTemplate.setEnableTransactionSupport(true);
                    redisTemplate.watch(lockName);
                    String identificationDB = redisTemplate.opsForValue().get(lockName);
                    if (identificationDB != null && identification != null && identificationDB.equals(identification)) {
                        redisTemplate.multi();
                        redisTemplate.expire(lockName, timeout, TimeUnit.SECONDS);
                        redisTemplate.exec();
                    }
                    redisTemplate.unwatch();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } catch (Exception e) {
                    Thread.currentThread().interrupt();

                } finally {
                    RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
                }
            }
        }
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中使用RedisTemplate实现Redis加写锁的步骤如下: 1. 创建RedisTemplate对象 RedisTemplate是Spring Data Redis提供的一个基于Jedis的Redis客户端。首先需要创建一个RedisTemplate对象,用于连接Redis服务器。可以使用以下代码创建一个RedisTemplate对象: ``` @Autowired private RedisTemplate<String, Object> redisTemplate; ``` 2. 获取锁 获取锁的过程可以采用Redis的setnx命令,该命令可以保证在多线程情况下只有一个线程能够获取到锁。如果当前锁已经被其他线程占用,则当前线程会等待一段时间后再次尝试获取锁,直到成功为止。可以使用以下代码实现锁的获取: ``` public boolean lock(String key, String value, long expireTime) { boolean result = redisTemplate.opsForValue().setIfAbsent(key, value); if (result) { redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); } return result; } ``` 其中,key表示锁的名称,value表示锁的值,expireTime表示锁的过期时间。 3. 释放锁 释放锁的过程可以采用Redis的del命令,该命令可以将锁从Redis中删除。可以使用以下代码实现锁的释放: ``` public void unlock(String key, String value) { Object currentValue = redisTemplate.opsForValue().get(key); if (currentValue != null && currentValue.equals(value)) { redisTemplate.delete(key); } } ``` 其中,key表示锁的名称,value表示锁的值。 完整代码如下: ``` @Component public class RedisLock { @Autowired private RedisTemplate<String, Object> redisTemplate; public boolean lock(String key, String value, long expireTime) { boolean result = redisTemplate.opsForValue().setIfAbsent(key, value); if (result) { redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); } return result; } public void unlock(String key, String value) { Object currentValue = redisTemplate.opsForValue().get(key); if (currentValue != null && currentValue.equals(value)) { redisTemplate.delete(key); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值