Redis的分布式锁及其实现Redisson

张开发
2026/4/19 5:00:43 15 分钟阅读

分享文章

Redis的分布式锁及其实现Redisson
前言分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源那么访问这些资源的时候往往需要互斥来防止彼此干扰来保证一致性这个时候便需要使用到分布式锁。什么是分布式锁1.在分布式环境中使用到的锁就是分布式锁2.在分布式环境中对不同应用程序操作的共享资源进行加锁就是分布式锁分布式环境1.同一个应用下的子应用采用单独部署的方式运行就是分布式2.只要应用存在跨JVM就是分布式环境为什么要有分布式锁JDK中原生锁Synchronized、Lock只针对是同一个JVM实例上操作资源而言对于不同JVM的操作是没办法进行加锁的。分布式锁的应用场景只要存在跨JVM操作并且存在共享资源竞争问题就是必须使用到分布式锁的场景。分布式锁有哪些常见的分布式锁有以下几种1.基于数据库乐观锁实现分布式锁2.基于Redis的分布式锁Redisson3.基于Zookeeper实现分布式锁基于redis分布式锁原理获取锁通过Redis创建一个唯一的key如果当前线程能创建这个唯一的key,则表示当前线程获取到锁。释放锁当删除Redis中的代表锁的唯一key,则表示释放锁。什么是死锁在释放锁时出现异常Redis中代表锁的唯一key未被删除而其他线程一直在自旋等待并希望能够获取锁但事实上所有线程都没能获取到锁的情况称为死锁。如何解决死锁我们可以通过对Redis中代表锁的唯一Key设置过期时间来避免死锁的发生。如何避免锁被其他线程释放创建锁时记录线程ID自己的锁只能自己释放。如何保证锁的可重入性当线程获取到锁后在Redis中把当前线程的ID做为key的值进行存储加锁时判断当前线程与Redis锁的值是否一致。基于redis分布式锁Redisson配置pom.xml?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdsite.yangpan/groupId artifactIdyangpan-spring-boot/artifactId version0.0.1-SNAPSHOT/version /parent groupIdsite.yangpan.redission/groupId artifactIdyangpan-spring-boot-redission/artifactId version0.0.1-SNAPSHOT/version nameyangpan-spring-boot-redission/name descriptionDemo project for Spring Boot/description properties java.version1.8/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !--下面这两个依赖就是集成redission的依赖-- !--第一个依赖与spring boot版本有关系参考官方文档-- dependency groupIdorg.redisson/groupId artifactIdredisson-spring-data-21/artifactId version3.13.3/version /dependency dependency groupIdorg.redisson/groupId artifactIdredisson-spring-boot-starter/artifactId version3.13.3/version /dependency /dependencies /project注意网上很多都是直接引入redission依赖但是我这里是通过Spring Boot Starter的方式引入配置application.properties# 公共spring boot配置 spring.redis.host127.0.0.1 spring.redis.port6379 spring.redis.password #spring.redis.cluster.nodes #spring.redis.sentinel.master #spring.redis.sentinel.nodes ## Redisson 配置 spring.redis.redisson.configclasspath:redisson.yaml配置redisson.yamlsingleServerConfig: idleConnectionTimeout: 10000 pingTimeout: 1000 # connectTimeout: 10000 timeout: 3000 retryAttempts: 3 retryInterval: 1500 # reconnectionTimeout: 3000 # failedAttempts: 3 password: subscriptionsPerConnection: 5 clientName: address: redis://127.0.0.1:6379 subscriptionConnectionMinimumIdleSize: 1 subscriptionConnectionPoolSize: 50 connectionMinimumIdleSize: 32 connectionPoolSize: 64 database: 0 # dnsMonitoring: false dnsMonitoringInterval: 5000 threads: 0 nettyThreads: 0 codec: !org.redisson.codec.JsonJacksonCodec {} #transportMode:NIO编写RedissonSpringDataConfig接下来我们注册 RedissonConnectionFactory 到 Spring contextpackage site.yangpan.redission.config; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.redisson.spring.data.connection.RedissonConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import java.io.IOException; /** * 注册 RedissonConnectionFactory 到 Spring context * https://github.com/redisson/redisson/tree/master/redisson-spring-data#spring-data-redis-integration * Created by yangpan on 2020-08-29 19:15. */ Configuration public class RedissonSpringDataConfig { Bean public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) { return new RedissonConnectionFactory(redisson); } Bean(destroyMethod shutdown) public RedissonClient redisson(Value(classpath:/redisson.yaml) Resource configFile) throws IOException { Config config Config.fromYAML(configFile.getInputStream()); return Redisson.create(config); } }使用Redisson这里我们直接编写一个controller然后使用Redissonpackage site.yangpan.redission.reentrantLock; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 基于Redis的Redisson分布式可重入锁RLock * Java对象实现了java.util.concurrent.locks.Lock接口。 * 同时还提供了异步Async、反射式Reactive和RxJava2标准的接口。 * Created by yangpan on 2020-08-29 19:40. */ Controller RestController RequestMapping(/redissionReentrantLock) public class RedissonReentrantLock { private Integer stock 100; Autowired private RedissonClient redissonClient; GetMapping(/test) public void test(){ //使用线程池模拟并发看分布式锁有没有问题 ExecutorService executorService Executors.newFixedThreadPool(8); for(int i0;i1000;i){ executorService.execute(() - { try { Thread.sleep(3000); //调用加锁方法 reduceStockRessionLock(); } catch (InterruptedException e) { e.printStackTrace(); } }); } } /** * 加锁情况 */ private void reduceStockRessionLock() { //获取锁可重入锁 RLock lock redissonClient.getLock(anyLock); //加锁 lock.lock(); //业务操作 if(stock 0){ stock--; System.out.println(当前库存剩余 stock); } //释放锁 lock.unlock(); } /** * 不加锁情况 */ private void reduceStock() throws InterruptedException { //业务操作 if(stock 0){ stock--; System.out.println(当前库存剩余 stock); } } }启动测试接下来我们启动项目访问接口查看日志观察日志分析可得Redisson分布式锁确实起到了作用curl http://localhost:8080/redissionReentrantLock/test

更多文章