# 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 |解锁 如果获取不到锁去解锁会存在异常 |