對於分布式服務的情況下,當只使用java原生相關鎖(ReentrantLock)操作時,只能保證一個jvm進程中的操作受到鎖的保護,但對於多個jvm進程就無法進行有效鎖保護控制;
因此為了滿足分布式場景, 需要使用一個統一管理位置,因此通過redis 來做作為鎖控制
spring 提供的redis支持
https://docs.spring.io/spring-integration/reference/html/redis.html#redis-lock-registry
其利用java 本地鎖和 redis SET相關指令 雙重保證
引入相關組件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-integration</artifactId> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
在application.yml中添加redis的配置
spring:
redis:
host: localhost # Redis服務器地址
database: 0 # Redis數據庫索引(默認為0)
port: 6379 # Redis服務器連接端口
password: # Redis服務器連接密碼(默認為空)
建立配置類,注入RedisLockRegistry
@Configuration
public class RedisLockConfiguration {
@Bean
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
return new RedisLockRegistry(redisConnectionFactory, "redis-lock");
}
}
@RestController
@Api(tags = "RedisLockRegistryController")
@RequestMapping("/redisLockRegistry")
@Slf4j
public class RedisLockRegistryController {
@Resource
private RedisLockRegistry redisLockRegistry;
@ApiOperation("加鎖")
@GetMapping(value = "/tryGetDistributedLock")
public void tryGetDistributedLock(@RequestParam String key, @RequestParam String value) {
Lock lock = redisLockRegistry.obtain("redis");
try {
//嘗試在指定時間內加鎖,如果已經有其他鎖鎖住,獲取當前線程不能加鎖,則返回false,加鎖失敗;加鎖成功則返回true
if (lock.tryLock(3, TimeUnit.SECONDS)) {
log.info("lock is ready");
TimeUnit.SECONDS.sleep(5);
}
} catch (InterruptedException e) {
log.error("obtain lock error", e);
} finally {
lock.unlock();
}
}
}
測試 啟動多個實例,分別訪問/lock/redis 端點,一個正常秩序業務邏輯,另外一個實例訪問出現如下錯誤,說明第二個實例沒有拿到鎖,證明了分布式鎖的存在。

