Spring Integration實現分布式鎖


學習本篇之前,可以先看下文章 什么是分布式鎖,了解下基本概念。

之前都是手寫一個分布式鎖,其實Spring早就提供了分布式鎖的實現。早期,分布式鎖的相關代碼存在於Spring Cloud的子項目Spring Cloud Cluster中,后來被遷移到Spring Integration中。

Spring Integration提供的全局鎖,目前為這幾種存儲提供了實現:Gemfire、JDBC、Redis、Zookeeper

它們使用相同的API抽象--這正是Spring最擅長的。這意味着,不論使用哪種存儲,你的編碼體驗都是一樣的,有一天想更換實現,只需要修改依賴和配置就可以了,無需修改代碼

 

下面以Redis為例,講解Spring Integration如何使用分布式鎖。

1、增加依賴:

<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>

2、配置文件增加redis配置:

spring:
  redis:
    port: 6379
    host: localhost

3、增加RedisLock的配置類:

@Configuration
public class RedisLockConfiguration {

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

}

4、增加測試方法:

@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個線程將獲取不到。說明鎖起作用了~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM