Spring Integration实现分布式锁

学习本篇以前,能够先看下文章 什么是分布式锁,了解下基本概念。html

以前都是手写一个分布式锁,其实Spring早就提供了分布式锁的实现。早期,分布式锁的相关代码存在于Spring Cloud的子项目Spring Cloud Cluster中,后来被迁移到Spring Integration中。redis

Spring Integration提供的全局锁,目前为这几种存储提供了实现:Gemfire、JDBC、Redis、Zookeeperspring

它们使用相同的API抽象--这正是Spring最擅长的。这意味着,不论使用哪一种存储,你的编码体验都是同样的,有一天想更换实现,只须要修改依赖和配置就能够了,无需修改代码app

 

下面以Redis为例,讲解Spring Integration如何使用分布式锁。分布式

一、增长依赖:spring-boot

<dependency>
    <!-- spring integration -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
    <!-- spring integration与redis结合,实现redis分布式锁 -->
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-redis</artifactId>
</dependency>
<dependency>
    <!-- redis -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

二、配置文件增长redis配置:工具

spring: redis: port: 6379 host: localhost

三、增长RedisLock的配置类:学习

@Configuration public class RedisLockConfiguration { @Bean public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) { return new RedisLockRegistry(redisConnectionFactory, "spring-cloud"); } }

四、增长测试方法:测试

@RestController @RequestMapping("redis") public class RedisController { @Autowired private RedisLockRegistry redisLockRegistry; private int num = 20; /** * 测试redis分布式锁(没有锁) */ @GetMapping("testUnLock") public void testUnLock() throws InterruptedException { String s = Thread.currentThread().getName(); if (num > 0) { System.out.println(s + "排号成功,号码是:" + num); num--; } else { System.out.println(s + "排号失败,号码已经被抢光"); } } /** * 测试redis分布式锁(有锁) */ @GetMapping("testLock") public void testLock() throws InterruptedException { Lock lock = redisLockRegistry.obtain("lock"); boolean isLock = lock.tryLock(1, TimeUnit.SECONDS); String s = Thread.currentThread().getName(); if (num > 0 && isLock) { System.out.println(s + "排号成功,号码是:" + num); num--; } else { System.out.println(s + "排号失败,号码已经被抢光"); } lock.unlock(); } }

使用压测工具(如:JMeter),开启25个线程,循环一次:编码

先测试一下没有加锁,会出现什么结果。请求 http://localhost:18081/redis/testUnLock:

http-nio-18081-exec-22排号成功,号码是:20 http-nio-18081-exec-28排号成功,号码是:19 http-nio-18081-exec-16排号成功,号码是:18 http-nio-18081-exec-30排号成功,号码是:17 http-nio-18081-exec-26排号成功,号码是:16 http-nio-18081-exec-15排号成功,号码是:15 http-nio-18081-exec-15排号成功,号码是:14 http-nio-18081-exec-3排号成功,号码是:14 http-nio-18081-exec-26排号成功,号码是:12 http-nio-18081-exec-15排号成功,号码是:11 http-nio-18081-exec-3排号成功,号码是:10 http-nio-18081-exec-15排号成功,号码是:9 http-nio-18081-exec-30排号成功,号码是:8 http-nio-18081-exec-26排号成功,号码是:7 http-nio-18081-exec-3排号成功,号码是:6 http-nio-18081-exec-15排号成功,号码是:5 http-nio-18081-exec-3排号成功,号码是:4 http-nio-18081-exec-26排号成功,号码是:3 http-nio-18081-exec-15排号成功,号码是:2 http-nio-18081-exec-3排号成功,号码是:1 http-nio-18081-exec-30排号失败,号码已经被抢光 http-nio-18081-exec-22排号成功,号码是:14 http-nio-18081-exec-28排号成功,号码是:14 http-nio-18081-exec-15排号成功,号码是:1 http-nio-18081-exec-16排号成功,号码是:12

从上面结果能够看到,num变量的有些值被多个线程同时获取,致使20个号被24个线程获取

再来试下加锁的,请求 http://localhost:18081/redis/testLock:

http-nio-18081-exec-2排号成功,号码是:20 http-nio-18081-exec-142排号成功,号码是:19 http-nio-18081-exec-141排号成功,号码是:18 http-nio-18081-exec-171排号成功,号码是:17 http-nio-18081-exec-152排号成功,号码是:16 http-nio-18081-exec-159排号成功,号码是:15 http-nio-18081-exec-154排号成功,号码是:14 http-nio-18081-exec-156排号成功,号码是:13 http-nio-18081-exec-142排号成功,号码是:12 http-nio-18081-exec-158排号成功,号码是:11 http-nio-18081-exec-172排号成功,号码是:10 http-nio-18081-exec-161排号成功,号码是:9 http-nio-18081-exec-160排号成功,号码是:8 http-nio-18081-exec-164排号成功,号码是:7 http-nio-18081-exec-162排号成功,号码是:6 http-nio-18081-exec-171排号成功,号码是:5 http-nio-18081-exec-170排号成功,号码是:4 http-nio-18081-exec-152排号成功,号码是:3 http-nio-18081-exec-165排号成功,号码是:2 http-nio-18081-exec-157排号成功,号码是:1 http-nio-18081-exec-168排号失败,号码已经被抢光 http-nio-18081-exec-159排号失败,号码已经被抢光 http-nio-18081-exec-166排号失败,号码已经被抢光 http-nio-18081-exec-163排号失败,号码已经被抢光 http-nio-18081-exec-177排号失败,号码已经被抢光

从上面结果能够看到,20个号挨个被20个线程获取,剩下5个线程将获取不到。说明锁起做用了~

相关文章
相关标签/搜索