# distributed-lock-example
**Repository Path**: logtail/distributed-lock-example
## Basic Information
- **Project Name**: distributed-lock-example
- **Description**: 优雅实现分布式锁
- **Primary Language**: Java
- **License**: AGPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-01-01
- **Last Updated**: 2022-01-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# distributed-lock-example
#### 介绍
优雅实现分布式锁
#### 软件架构
软件架构说明
#### 基于Reids实现
### 引入依赖
```xml
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
org.springframework.boot
spring-boot-starter-integration
org.springframework.integration
spring-integration-redis
```
### properties配置
```properties
server.port=9000
spring.application.name=distributed-lock-example
spring.redis.host=localhost
spring.redis.password=123456
spring.redis.port=6789
spring.redis.database=0
spring.redis.lettuce.pool.max-active=16
spring.redis.lettuce.pool.max-wait=3000
spring.redis.lettuce.pool.min-idle=1
spring.redis.lettuce.pool.max-idle=8
spring.redis.timeout=30000
```
### 代码配置
```java
package cn.zwx.distributed.lock.example.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* redis 配置类
*/
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
//设置序列化
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
//指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// DefaultTyping有四个选项:
// JAVA_LANG_OBJECT: 当对象属性类型为Object时生效;
// OBJECT_AND_NON_CONCRETE: 当对象属性类型为Object或者非具体类型(抽象类和接口)时生效;
// NON_CONCRETE_AND+_ARRAYS: 同上, 另外所有的数组元素的类型都是非具体类型或者对象类型;
// NON_FINAL: 对所有非final类型或者非final类型元素的数组。
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//配置redisTemplate
RedisTemplate redisTemplate = new RedisTemplate<>();
// 配置连接工厂
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer stringSerializer = new StringRedisSerializer();
//key序列化
redisTemplate.setKeySerializer(stringSerializer);
//value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
//Hash value序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
```
```java
package cn.zwx.distributed.lock.example.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;
/**
* 分布式锁配置类
*/
@Configuration
public class RedisLockConfiguration {
@Value("${spring.application.name}")
private String appName;
@Bean
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory){
return new RedisLockRegistry(redisConnectionFactory,appName+"-redis-lock");
}
}
```
### 代码示例
```java
package cn.zwx.distributed.lock.example.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.messaging.MessagingException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
@RestController
@RequestMapping("/distribute")
public class DistributeLockController {
private Logger logger = LoggerFactory.getLogger(DistributeLockController.class);
@Resource
private RedisLockRegistry redisLockRegistry;
@RequestMapping("/redis/lock")
public String testDistributeLockForRedis(){
String redisLockKey = "distribute-redis-lock" ;
Lock lock = redisLockRegistry.obtain(redisLockKey);
try {
// if (!lock.tryLock(100, TimeUnit.MILLISECONDS)){
if (!lock.tryLock()){
return "业务正在处理中,请稍后进行重试!";
}
// 第一个参数 是获取锁等待的时间
logger.info("获取redisLock:{}锁成功",redisLockKey);
// 模拟业务处理
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
return "获取分布式失败,请稍后进行重试!";
}finally {
logger.info("释放redisLock:{}",redisLockKey);
try {
lock.unlock();
}catch (IllegalStateException e){
logger.info("释放redisLock:{}异常",redisLockKey,e);
}
}
return "业务处理完成!!";
}}
```
#### 基于zookeeper实现
###依赖导入
```xml
org.springframework.boot
spring-boot-starter-integration
org.springframework.integration
spring-integration-zookeeper
```
### properties配置
```properties
server.port=9000
spring.application.name=distributed-lock-example
zookeeper.hosts=localhost:2181,localhost:2182,localhost:2183
```
### 代码配置
```java
package cn.zwx.distributed.lock.example.config;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.zookeeper.config.CuratorFrameworkFactoryBean;
import org.springframework.integration.zookeeper.lock.ZookeeperLockRegistry;
/**
* 基于zk实现分布式锁
*/
@Configuration
public class ZookeeperLockConfig {
@Value("${zookeeper.hosts}")
private String zkUrl;
@Value("${spring.application.name}")
private String appName;
@Bean
public CuratorFrameworkFactoryBean curatorFrameworkFactoryBean(){
return new CuratorFrameworkFactoryBean(zkUrl);
}
@Bean
public ZookeeperLockRegistry zookeeperLockRegistry(CuratorFramework curatorFramework){
return new ZookeeperLockRegistry(curatorFramework,"/"+appName+"/lock");
}
}
```
### 代码示例
```java
package cn.zwx.distributed.lock.example.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.zookeeper.lock.ZookeeperLockRegistry;
import org.springframework.messaging.MessagingException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
@RestController
@RequestMapping("/distribute")
public class DistributeLockController {
private Logger logger = LoggerFactory.getLogger(DistributeLockController.class);
@Resource
private ZookeeperLockRegistry zookeeperLockRegistry;
@RequestMapping("/zk/lock")
public String testDistributeLockForZk(){
String redisLockKey = "distribute-zk-lock" ;
Lock lock = zookeeperLockRegistry.obtain(redisLockKey);
try {
// if (!lock.tryLock(100, TimeUnit.MILLISECONDS)){
if (!lock.tryLock()){
return "业务正在处理中,请稍后进行重试!";
}
// 第一个参数 是获取锁等待的时间
logger.info("获取zkLock:{}锁成功",redisLockKey);
// 模拟业务处理
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
return "获取分布式失败,请稍后进行重试!";
}finally {
logger.info("释放zkLock:{}",redisLockKey);
try {
lock.unlock();
}catch (MessagingException e){
logger.info("释放zkLock:{}异常",redisLockKey,e);
}
}
return "业务处理完成!!";
}
}
```
#### 使用说明
| 方法名 | 描述 |
| :--- | :---- |
| lock() |加锁,如果已经被其他线程抢占到锁
或者当前线程不能获取锁则阻塞 |
| lockInterruptibly() | 加锁,除非当前线程被打断 |
| tryLock() | 尝试加锁,如果锁被占用则获取线程不能获得锁
返货false否则返回true |
| tryLock(long,TimeUnit unit) | 尝试在指定时间内加锁,
如果锁被占用那么当前线程,不能获取锁
返回false,否则返回true |
| unlock |解锁 如果获取不到锁去解锁会存在异常 |