首页 > 数据库 >Redisson分布式锁的实现

Redisson分布式锁的实现

时间:2023-11-15 15:11:23浏览次数:47  
标签:Redisson return String 实现 lock RLock lockKey public 分布式

分布式锁

在多线程环境下,如果多个线程同时访问共享资源(数据库),往往会发生数据竞争。要想在某一线程访问资源时,令其他线程阻塞等待,就需要使用分布式锁,确保共享资源同时只有一个线程访问。

实现思路:
向Redis中插入同一key:
A插入key,如果成功则获取到锁,B再来插入式发现key已经存在了,则失败,无法获取到锁,知道A将key删除。

为确保锁可用,我们需要在确保锁的实现时,同时满足四个条件:
1、互斥性:任意时刻,只有一个客户端持有锁
2、不发生死锁:即使有一个客户端在持有锁的期间崩溃而没有解锁,后续客户端也能正常加锁
3、加锁和解锁必须是同一个客户端,客户端不能解开其他客户端的锁
4、容错性:只要大多数Redis节点能正常运行,客户端就能正常获取和释放锁

死锁的产生条件
1、互斥:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2、请求和保持:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3、不剥夺:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4、环路等待:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

使用Jedis简单实现分布式锁

这里使用Jedis简单完成了一个分布式锁:

// 定时任务注解,在生产环境的多实例下会同时执行,出现竞争问题
@Scheduled(cron = "*/30 * * * * *") 
public void timeTask(){  
    Jedis jedis = new Jedis(redisServerAddress,Integer.parseInt(redisServerPort));  
    jedis.auth(redisServerAuth);  
    // 尝试获取锁,TIME_OUT为超时时间
    String result = jedis.set(LOCK_KEY, "locked","nx","ex",TIME_OUT);  
    if(result!=null) {  
        try {  
            logger.info("进入定时任务");  
            // 在这里执行定时任务
        } catch (Exception e) {  
            throw new Exception;
        } finally {  
            jedis.del(LOCK_KEY);  
            jedis.close();  
        }  
    }  
}

Redisson实现分布式锁

Redisson简介

在Jedis的基础上,我们可以引用Redisson:是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。

Redisson基于Java实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。

配置Redisson

maven引入

<dependency> 
	<groupId>org.redisson</groupId> 
	<artifactId>redisson</artifactId> 
	<version>${redisson.version}</version> 
</dependency>

Config配置

实现一个RedissonConfig配置类
配置声明在application.properties

/**  
 * RedissonConfig * 
 * @author liyutao  
 * @version 2023/08/31 15:53  
 **/
 @Configuration  
public class RedissonConfig {  
    @Value("${redis.host}")  
    private String redisServerAddress;  
  
    @Value("${redis.pwd}")  
    private String redisServerAuth;  
  
    @Value("${redis.port}")  
    private String redisServerPort;  
  
    @Value("${redis.database}")  
    private String redisServerDatabase;  
  
    @Bean  
    public RedissonClient getClient(){  
        Config config = new Config();  
        config.useSingleServer().setAddress("redis://"+redisServerAddress+":"+redisServerPort)  
                .setPassword(redisServerAuth)  
                .setDatabase(Integer.parseInt(redisServerDatabase));  
        return Redisson.create(config);  
    }  
  
}

实现RLocker类,完成常用的加锁/解锁方法

/**  
 * RLocker * 
 * @author liyutao  
 * @version 2023/08/31 15:40  
 **/@Component  
public class RLocker {  
    @Autowired  
    private RedissonClient redissonClient;  
  
    public static final Long R_LOCK_DEFAULT_WAIT_TIME = 5L;//默认等待时间  
  
    public static final Long R_LOCK_DEFAULT_LEASE_TIME = 15L;//默认超时时间  
  
  
    /**  
     * 获取锁,并且加锁  
     * 若未拿到锁,则线程block  
     * @return RLock lock  
     * @author NoFat  
     **/    
     public RLock lock(String lockKey){  
        RLock lock = redissonClient.getLock(lockKey);  
        lock.lock();  
        return lock;  
    }  
  
    /**  
     * 获取锁,并且加锁(超时时间为timeout秒)  
     * 若未拿到锁,则线程block  
     * @return RLock lock  
     * @author NoFat  
     **/    
     public RLock lock(String lockKey,long timeout){  
        RLock lock = redissonClient.getLock(lockKey);  
        lock.lock(timeout, TimeUnit.SECONDS);  
        return lock;  
    }  
  
    /**  
     * 获取锁,并且加锁(超时时间为timeout,单位为timeUnit)  
     * 若未拿到锁,则线程block  
     * @return RLock lock  
     * @author NoFat  
     **/    
     public RLock lock(String lockKey,long timeout,TimeUnit timeUnit){  
        RLock lock = redissonClient.getLock(lockKey);  
        lock.lock(timeout, timeUnit);  
        return lock;  
    }  
  
    /**  
     * 在waitTime时间内尝试获取锁,并加锁  
     * waitTime时间后,结束等待,返回false  
     * leaseTime时间后,锁过期  
     * @return boolean result  
     * @author NoFat  
     **/    
     public boolean tryLock(String lockKey,long waitTime,long leaseTime,TimeUnit timeUnit){  
        RLock lock = redissonClient.getLock(lockKey);  
        try {  
            return lock.tryLock(waitTime,leaseTime,timeUnit);  
        } catch (InterruptedException e) {  
            return false;  
        }  
    }  
  
    /**  
     * 在默认等待时间内尝试获取锁,并加锁  
     * 在默认超时时间后,结束等待,返回false  
     * leaseTime时间后,锁过期  
     * @return boolean result  
     * @author NoFat  
     **/    
     public boolean tryLock(String lockKey){  
        RLock lock = redissonClient.getLock(lockKey);  
        try {  
            return lock.tryLock(R_LOCK_DEFAULT_WAIT_TIME,R_LOCK_DEFAULT_LEASE_TIME,TimeUnit.SECONDS);  
        } catch (InterruptedException e) {  
            return false;  
        }  
    }  
  
    /**  
     * 解锁  
     * @author NoFat  
     **/    
     public void unlock(String lockKey) {  
        RLock lock = redissonClient.getLock(lockKey);  
        lock.unlock();  
    }  
  
    /**  
     * 解锁  
     * @author NoFat  
     **/    
     public void unlock(RLock lock) {  
        lock.unlock();  
    }  
}

以上就完成了Redisson的一个简单配置。
接下来,就可以使用RLocker类的方法,实现一个简单的分布式锁,来避免多线程下的资源冲突问题。

Redisson分布式锁-代码示例

@Autowired  
private RLocker rLocker;  
  
private static final String LOCK_KEY = "MY_KEY";  
private static final Long WAIT_TIME = 5L;//等待时间  
  
private static final Long LEASE_TIME = 15L;//超时时间  
  
// 定时任务注解,在生产环境的多实例下会同时执行,出现竞争问题
@Scheduled(cron = "*/30 * * * * *")  
public void timeTask(){  
    //获取锁  
    boolean result = rLocker.tryLock(LOCK_KEY,WAIT_TIME,LEASE_TIME,TimeUnit.SECONDS);  
    try {  
        if(result){  
            logger.info("进入定时任务");  
            // 这里执行定时任务
        }  
    } catch (Exception e){  
        throw new ZTBusinessException(BaseRspConstants.RSP_DESC_DB_ERROR);  
    } finally {  
        if(result){  
            rLocker.unlock(LOCK_KEY);  
        }  
    }  
}

标签:Redisson,return,String,实现,lock,RLock,lockKey,public,分布式
From: https://www.cnblogs.com/nofatter/p/17833907.html

相关文章

  • 打造天籁之音,Audition 2024实现你的音乐梦想!
    Audition2024是一款非常专业的音频编辑和混音软件,它可以帮助用户进行高质量的音频处理和混音操作。这款软件具有强大的音频处理功能,可以让用户进行音频剪辑、降噪、均衡、压缩、效果处理等操作,并且支持多种音频格式的导入和导出。→→↓↓载Audition2024mac/win版首先,Auditi......
  • 贷款额度图片生成器,在线制作成功审核通过,易语言画板生成实现
    用易语的画板加了一个网上贷款额度申请图+通过图,原有信息都被PS擦掉了,被擦掉的部分我加入了自己黑月透明标签,然后加了很多的编辑框,而编辑框是通过用户输入信息的,它都对应着每一个标签信息,我们点击按钮后要实现的功能就是标签的内容=编辑框这种效果,然后审核通过部分要加一些标签和......
  • elk分布式日志系统2
    《接着上篇文章elk分布式日志系统1,继续学习》 【Filebeat+Logstash+es】  --------------------------filter不做任何处理,直接输出到logstash----------------------------  1,输出日志到logstash 编辑配置文件filebeat.yml,  关闭output.elasticsearch配置   2,编......
  • android开发Flutter Text自动换行实现
    flutter自动换行处理flutter自动换行有几种场景:column中,row中在Column中的Text不用任何处理,能够自动换行。在Row中的Text需要用Expanded包裹。因为文字是水平方向排放的,和Row的计算规则冲突,需要使用Expanded包裹,表示剩下的给Text,Text自然知道自身宽度,才能实现自动换行。Row(cro......
  • 贷款额度图片生成器,在线制作成功审核通过,易语言画板生成实现
    用易语的画板加了一个网上贷款额度申请图+通过图,原有信息都被PS擦掉了,被擦掉的部分我加入了自己黑月透明标签,然后加了很多的编辑框,而编辑框是通过用户输入信息的,它都对应着每一个标签信息,我们点击按钮后要实现的功能就是标签的内容=编辑框这种效果,然后审核通过部分要加一些标签和图......
  • 本地Elasticsearch 结合内网穿透实现远程连接
    Elasticsearch是一个基于Lucene库的分布式搜索和分析引擎,它提供了一个分布式、多租户的全文搜索引擎,具有HTTPWeb接口和无模式JSON文档,同时也是是一个非常强大的工具,可以用于各种用途,例如日志分析、搜索引擎、安全分析等等。远程连接的好处在于可以让用户从远程位置访问Elastics......
  • 云原生雪花改进型分布式id服务
    1,概述一个基于雪花改进型分布式id基础服务demo地址:http://uid.activeclub.site/web/v1/uuid/get1.1,入参样例:请求路径:GEThttp://{url}:{port}/web/uuid/get入参说明:类目字段名说明url对外暴露的IP或者域名本地启动一般为127.0.0.1或者localhostport对外暴......
  • 一步一步实现kbmmw的httpsys使用https功能
    感谢xalion,为我们详细写的文档《一步一步实现kbmmw的httpsys使用https功能》,以下为原文:kbmmw的httpsys的功能已经实现了好长时间,但是现在各个平台都要求使用https来提供服务。今天一步一步来说一下如何使用kbmmw 的httpsys功能支持https.首先为了获得证书,我们可以使用阿里云申请一......
  • 如何用SSH密钥实现加密和电子签名?
    SSH(SecureShell)密钥对可用于实现加密和数字签名,以确保数据的机密性和完整性。以下是使用SSH密钥进行加密和数字签名的基本步骤:1.生成SSH密钥对:在本地计算机上生成SSH密钥对,这包括私钥和公钥。使用以下命令生成:ssh-keygen-trsa-b2048这将生成一个2048位的RSA密钥对。您将被提......
  • 实现批量插入和更新(mysql)
    在实际数据库应用中,经常需要实现插入或更新(插入新数据,如果已存在则更新已有数据)的功能。然而,在处理大量数据时,频繁的数据库I/O操作可能导致性能问题。MySQL批量插入和更新使用INSERT...ONDUPLICATEKEYUPDATEMySQL提供了INSERT...ONDUPLICATEKEYUPDATE语法,通......