深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁

多节点的部署中,对锁的控制,参考:

http://www.jeffkit.info/2011/07/1000/

直接贴上代码实现,同上一篇文章一样,都是基于AOP

定义注解,标志切入点:

package com.ns.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisLock {
    /**
     * redis的key
     * @return
     */
    String value();
    /**
     * 持锁时间,单位毫秒,默认一分钟
     */
    long keepMills() default 60000;
    /**
     * 当获取失败时候动作
     */
    LockFailAction action() default LockFailAction.GIVEUP;

    public enum LockFailAction{
        /**
         * 放弃
         */
        GIVEUP,
        /**
         * 继续
         */
        CONTINUE;
    }
    /**
     * 睡眠时间,设置GIVEUP忽略此项
     * @return
     */
    long sleepMills() default 1000;
}

切面实现:

package com.ns.redis.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.ns.annotation.RedisLock;
import com.ns.annotation.RedisLock.LockFailAction;
import com.ns.redis.dao.base.BaseRedisDao;

@Aspect
public class RedisLockAspect extends BaseRedisDao<String, Long>{
    private static final Logger log = LoggerFactory.getLogger(RedisLockAspect.class);
    //execution(* com.ns..*(*,..)) and @within(com.ns.annotation.RedisLock)

    @Pointcut("execution(* com.ns..*(..)) && @annotation(com.ns.annotation.RedisLock)")
    private void lockPoint(){}

    @Around("lockPoint()")
    public Object arround(ProceedingJoinPoint pjp) throws Throwable{
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();
        RedisLock lockInfo = method.getAnnotation(RedisLock.class);

        boolean lock = false;
        Object obj = null;
        while(!lock){
            long timestamp = System.currentTimeMillis()+lockInfo.keepMills();
            lock = setNX(lockInfo.value(), timestamp);
            //得到锁,已过期并且成功设置后旧的时间戳依然是过期的,可以认为获取到了锁(成功设置防止锁竞争)
            long now = System.currentTimeMillis();
            if(lock || ((now > getLock(lockInfo.value())) && (now > getSet(lockInfo.value(), timestamp)))){
                //得到锁,执行方法,释放锁
                log.info("得到锁...");
                obj = pjp.proceed();
                //不加这一行,对于只能执行一次的定时任务,时间差上不能保证另一个一定正好放弃
                if(lockInfo.action().equals(LockFailAction.CONTINUE)){
                    delete(lockInfo.value());
                }
            }else{
                if(lockInfo.action().equals(LockFailAction.CONTINUE)){
                    log.info("稍后重新请求锁...");
                    Thread.currentThread().sleep(lockInfo.sleepMills());
                }else{
                    log.info("放弃锁...");
                    break;
                }
            }
        }
        return obj;
    }
    public boolean setNX(String key,Long value){
        return valueOperations.setIfAbsent(key, value);
    }
    public long getLock(String key){
        return valueOperations.get(key);
    }
    public Long getSet(String key,Long value){
        return valueOperations.getAndSet(key, value);
    }
    public void releaseLock(String key){
        delete(key);
    }
}

以上有些代码只符合我现在的项目场景,根据实际需要进行调整

时间: 2025-01-06 07:12:22

深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁的相关文章

Redis 4.0.10 文档(分布式锁)

Redis分布式锁 在许多环境中,分布式锁是一种非常有用的原语,其中不同的进程必须以互斥的方式与共享资源一起运行. 有许多库和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都使用不同的方法,而且许多库使用的是一种简单的方法,与稍微复杂的设计相比,可以获得较低的保障. 此页面试图提供一种更典型的算法来使用Redis实现分布式锁,我们提出了一种称为Redlock的算法,它实现了一种我们认为比vanilla单实例方法更安全的DLM,我们希望社区将对其进行分析,提供反馈,并将其

redis之(九)redis的事务机制

[一]什么是redis的事务 --->redis的事务是一组命令的集合. --->redis的事务是保证一组命令,要么都执行,要么都不执行.但不支持一组命令中,其中一个或多个执行失败,不支持数据回滚.数据的一致性,由程序员控制. --->redis的事务还能保证一个事务内的命令依次执行,而不被其他命令插入.试想,客户端 A发送几条命令到redis服务器,客户端B也送了一条命令也到redis服务器上.如果不使用事务,则客户端 B的那条命令就有可能在客户端A的那几条命令中间执行. [二]re

Spring Boot (33) 分布式锁

上一篇中使用的Guava Cache,如果在集群中就不可以用了,需要借助Redis.Zookeeper之类的中间件实现分布式锁. 导入依赖 在pom.xml中需要添加的依赖包:stater-web.starter-aop.starter-data-redis <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot

Redlock(redis分布式锁)原理分析

Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击): 官网文档地址如下:https://redis.io/topics/distlock 这个锁的算法实现了多redis实例的情况,相对于单redis节点来说,优点在于 防止了 单节点故障造成整个服务停止运行的情况:并且在多节点中锁的设计,及多节点同时崩溃等各种意外情况有自己独特的设计方法: 此博客或

面试官:聊聊你对分布式锁技术方案的理解

前言 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题. 第一步,自身的业务场景: 在我日常做的项目中,目前涉及了以下这些业务场景: 场景一:比如分配任务场景.在这个场景中,由于是公司的业务后台系统,主要是用于审核人员的审核工作,并发量并不是很高,而且任务的分配规则设计成了通过审核人员每次主动的请求拉取,然后服务端从任务池中随机的选取任务进行分配.这个场景看到这里你会觉得比较单一,但是实际的分配过程中,由于涉及到了按

Spring Boot整合分布式锁

SpringBoot?是为了简化?Spring?应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程 重复提交(分布式) 单机版中我们用的是Guava Cache,但是这玩意存在集群的时候就凉了,所以我们还是要借助类似Redis.ZooKeeper 之类的中间件实现分布式锁. 本章目标 利用?自定义注解.Spring Aop.Redis Cache?实现分布式锁

什么是分布式锁及正确使用redis实现分布式锁

分布式锁 分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性. 举个不太恰当的例子:假设共享的资源就是一个房子,里面有各种书,分布式系统就是要进屋看书的人,分布式锁就是保证这个房子只有一个门并且一次只有一个人可以进,而且门只有一把钥匙.然后许多人要去看书,可以,排队,第一个人拿着钥匙把门打开进屋看书并且把门锁上,然后第二个人没有钥匙,那就等着,等第一个出来,然后你在拿着钥匙进去,然后就是以此类推 实现原理 互斥性 保证同一时间只有一个客户端可以拿到锁,也就是可

分布式锁三种实现方式(数据库实现,缓存Redis等,Zookeeper)

分布式锁三种实现方式: 1. 基于数据库实现分布式锁: 2. 基于缓存(Redis等)实现分布式锁: 3. 基于Zookeeper实现分布式锁: 一, 基于数据库实现分布式锁 1. 悲观锁 利用select … where … for update 排他锁 注意: 其他附加功能与实现一基本一致,这里需要注意的是“where name=lock ”,name字段必须要走索引,否则会锁表.有些情况下,比如表不大,mysql优化器会不走这个索引,导致锁表问题. 2. 乐观锁 所谓乐观锁与前边最大区别在

SpringBoot电商项目实战 — Redis实现分布式锁

最近有小伙伴发消息说,在Springboot系列文第二篇,zookeeper是不是漏掉了?关于这个问题,其实我在写第二篇的时候已经考虑过,但基于本次系列文章是实战练习,在项目里你能看到Zookeeper相关内容的也只有dubbo注册地址了.因为Zookeeper在项目中,我们不需要做任何配置和代码,只需要在服务器上安装一个Zookeeper应用即可. 包括对Zookeeper的依赖,我们在SpringBoot项目中只需要依赖Dubbo就ok了.在本次系列实战中,我是本着少说多动手的原则,如果有些

基于redis的分布式锁的分析与实践

转:https://my.oschina.net/wnjustdoit/blog/1606215 前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于线程之间是否相互阻塞. 那么,本文主要来讨论基于redis的分布式锁算法问题. 从2.6.12版本开始,redis为SET命令增加了一系列选项(SET key value [EX seconds] [PX