**目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题就存在问题,解决方案分布式锁。**

下面介绍两种首先分布式锁的方案:

1. **基于Spring Integration实现分布式锁**

2. **基于redisson实现分布式锁**

优缺点:第一种引入简单,使用方便,但只支持重入锁。第二种较第一种麻烦一点点,但支持重入锁、公平锁、读锁、写锁等多种类型。

**第一种方案**:提供的全局锁目前为以下存储提供了实现

Gemfire

JDBC

Redis

Zookeeper

因为第二种方案基于redis存储,为了方便该方案讲解选择redis作为存储。同时项目都采用springboot方式。

1. 首先创建springboot项目,添加基本依赖及redis、integration-redis依赖。如果选择其他存储方式,添加对应的integration依赖即可,无需更改业务,非常方便。

```

<!--integration-->

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-redis</artifactId>

</dependency>

<!--redis-->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.session</groupId>

<artifactId>spring-session-data-redis</artifactId>

</dependency>

<dependency>

<groupId>org.redisson</groupId>

<artifactId>redisson-spring-boot-starter</artifactId>

<version>3.9.1</version>

<exclusions>

<exclusion>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</exclusion>

</exclusions>

</dependency>

```

2. 添加yml配置

```

spring:

http:

encoding:

charset: UTF-8

force: true

enabled: true

server:

port: 8080

mvc:

static-path-pattern: /**

resources:

static-locations: classpath:/static/

redis:

database: 1

host: xx.xx.xx.xx

port: 6379

password: xxx

jedis:

pool:

max-active: 8

max-idle: 8

min-idle: 0

redisson:

address: "xxxx"

password: xxx

```

3. 创建config配置,RedisLockRegistry的第三个参数设置为上锁以后xxx秒自动解锁的时间,默认60s。

```java

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;

/**

* 描述:spring-integration-redis锁配置

*

* @Auther: gc.x

* @Date: 2019/10/28

*/

@Configuration

public class RedisLockConfiguration {

@Bean

public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory){

return new RedisLockRegistry(redisConnectionFactory,"spring-integration-redis",60000L);

}

}

```

4. 选择基于注解的形式加锁,先自定义锁注解,然后创建对应的切面

**@interface**

```java

/**

* 描述: 基于spring-integration-redis实现分布式锁

* 只支持重入锁ReentrantLock

* @Auther: gc.x

* @Ddate:2019/10/28

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface LockDistributed {

/**

* 锁的名称

* @return

*/

String name() default "";

/**

* 尝试加锁 最多等待时间

* @return

*/

int time() default 30;

/**

* 自定义业务key

* @return

*/

String [] keys() default {};

/**

* 上锁以后xxx秒自动解锁

*

*/

/**

*上锁以后xxx秒自动解锁

* long leaseTime();

* 在RedisLockConfiguration里面配置,如果要使用该参数,需要在切面里面new RedisLockRegistry

* @return

*/

}

```

**Aspect**

主要就是拦截自定义的注解,获取数据生成lockname,及竞争锁时间,

redisLockRegistry.obtain方法获取锁,

lock.tryLock方法竞争锁

由于篇幅省略了部分私有方法,不用纠结,结尾会提供完整源码

---getKeyName是获取自定义的作用于参数上的一个注解,可以将传入的参数作为 lockname的一部分,增强锁的力度。

---getName获取完整路径的方法名。

```java

/**

* 描述:添加了 LzxLockDistributed 注解 的Aop

*

* @Auther: gc

* @Date: 2019/6/18 10:56

*/

@Component

@Aspect

@Slf4j

public class LockAspect {

/**

* 锁前缀名

*/

public static final String LOCK_NAME_PREFIX = "lock";

/**

* 分隔符

*/

public static final String LOCK_NAME_SEPARATOR = ".";

/**

* 表达式解析器

*/

private ExpressionParser parser = new SpelExpressionParser();

/**

* 参数解析

*/

private ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

@Autowired

private RedisLockRegistry redisLockRegistry;

/* @Autowired

private RedisConnectionFactory redisConnectionFactory;*/

@Around(value = "@annotation(lockDistributed)")

public Object aroundApi(ProceedingJoinPoint point, LockDistributed lockDistributed) throws Throwable {

MethodSignature signature = (MethodSignature) point.getSignature();

String businessKeyName = getKeyName(point,lockDistributed);

String lockName = LOCK_NAME_PREFIX+LOCK_NAME_SEPARATOR + getName(lockDistributed.name(), signature) + businessKeyName;

log.info("lockName===>"+lockName);

// RedisLockRegistry redisLockRegistry=new RedisLockRegistry(redisConnectionFactory,"spring-integration-redis",lockDistributed.leaseTime());

Lock lock = redisLockRegistry.obtain(lockName);

boolean currentThreadLock = false;

Object proceed = null;

try{

currentThreadLock = lock.tryLock(lockDistributed.time(), TimeUnit.SECONDS);

Home("获取锁====="+currentThreadLock);

if (!currentThreadLock) {

throw new TimeoutException("获取锁资源等待超时");

}

proceed = point.proceed();

}catch (Exception e){

throw e;

}finally {

if(currentThreadLock){

lock.unlock();

}

}

return proceed;

}

}

```

5. 测试锁

```java

@RestController

public class DistributedLock {

@LockDistributed

@RequestMapping("/redisLockTest")

public void redisLockTest() {

System.out.println("获取锁,执行");

try {

Thread.sleep(20*1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("结束-------------------->>>>>>>>>>>>>>");

}

}

```

**第二种方案**:提供多种锁实现

1. 同理导入依赖

2. 配置yml

3. 创建config

```java

@Configuration

@ConditionalOnClass(Config.class)

@EnableConfigurationProperties(RedissonProperties.class)

public class RedissonAutoConfiguration {

@Autowired

private RedissonProperties redssionProperties;

/**

* 单体的

* @return

*/

@Bean

@ConditionalOnProperty(value = "redisson.address")

public RedissonClient redissonSingle(){

Config config = new Config();

SingleServerConfig serverConfig = config.useSingleServer().setAddress(redssionProperties.getAddress())

.setTimeout(redssionProperties.getTimeout())

.setDatabase(redssionProperties.getDatabase())

.setConnectionPoolSize(redssionProperties.getConnectionPoolSize())

.setConnectionMinimumIdleSize(redssionProperties.getConnectionMinimumIdleSize());

if(StringUtils.isNotEmpty(redssionProperties.getPassword())){

serverConfig.setPassword(redssionProperties.getPassword());

}

return Redisson.create(config);

}

/**

* 集群的

* @return

*/

@Bean

@ConditionalOnProperty(value = "redisson.masterAddresses")

public RedissonClient redissonSentinel(){

Config config = new Config();

ClusterServersConfig serverConfig = config.useClusterServers().addNodeAddress(redssionProperties.getSentinelAddresses())

.setTimeout(redssionProperties.getTimeout())

//设置集群扫描时间

.setScanInterval(redssionProperties.getScanInterval())

//主节点线程池数量

.setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize())

//从节点线程池数量

.setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize());

if(StringUtils.isNotEmpty(redssionProperties.getPassword())){

serverConfig.setPassword(redssionProperties.getPassword());

}

return Redisson.create(config);

}

```

4. 自定义注解,属性多了锁类型

```java

/**

* 描述: 基于redisson实现分布式锁

* 支持多种锁类型

* @Auther: gc.x

* @Ddate:2019/10/28

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface LockDistributed2 {

/**

* 锁的名称

* @return

*/

String name() default "";

/**

* 锁类型,默认可重入锁

* @return

*/

LockType lockType() default LockType.Reentrant;

/**

* 尝试加锁,最多等待时间

* @return

*/

long waitTime() default 60;

/**

*上锁以后xxx秒自动解锁

* @return

*/

long leaseTime() default 60*5;

/**

* 自定义业务key

* @return

*/

String [] keys() default {};

}

```

5. 切面,和方案一类似,主要根据注解上的锁类型获取对应的redisson提供的锁。

该实现内容较多不贴出来了,结构如下

![在这里插入图片描述](https://img-blog.csdnimg.cn/2019102915232952.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNDYwMTk4,size_16,color_FFFFFF,t_70)

```java

/**

* @Auther: gc.x

* @Date: 2019/10/28

* @Description:

*/

@Aspect

@Component

@Slf4j

public class LockAspect2 {

/**

* 锁前缀名

*/

public static final String LOCK_NAME_PREFIX = "lock";

/**

* 分隔符

*/

public static final String LOCK_NAME_SEPARATOR = ".";

/**

* 表达式解析器

*/

private ExpressionParser parser = new SpelExpressionParser();

/**

* 参数解析

*/

private ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

@Autowired

private LockFactory lockFactory;

@Around(value = "@annotation(lockDistributed2)")

public Object around(ProceedingJoinPoint joinPoint, LockDistributed2 lockDistributed2) throws Throwable{

// 获取方法

MethodSignature signature = (MethodSignature) joinPoint.getSignature();

// 获取锁类型

LockType type= lockDistributed2.lockType();

String businessKeyName = getKeyName(joinPoint,lockDistributed2);

String lockName = LOCK_NAME_PREFIX+LOCK_NAME_SEPARATOR + getName(lockDistributed2.name(), signature) + businessKeyName;

Home("lockName===>"+lockName);

long waitTime = lockDistributed2.waitTime();

long leaseTime =lockDistributed2.leaseTime();

LockInfo lockInfo = new LockInfo(type,lockName,waitTime,leaseTime);

ILock ilock = lockFactory.getLock(lockInfo);

boolean currentThreadLock = false;

try {

currentThreadLock = ilock.acquire();

if (!currentThreadLock) {

throw new TimeoutException("获取锁资源等待超时");

}

return joinPoint.proceed();

} finally {

if (currentThreadLock) {

ilock.release();

}

}

}

```

6. 同理测试,结束

附上码云:[https://gitee.com/giteeClass/project](https://gitee.com/giteeClass/project)

spring 锁_分布式锁-快速实战相关推荐

  1. java分布式_分布式锁的四种JAVA实现方式

    前言 作为这一段时间学习分布式锁的总结,本文总结了四种Java分布式锁的实现方式,简单编写了代码,进行模拟实现.相关代码存放在我的github仓库. 为什么要用锁 系统内,有多个消费者,需要对同一共享 ...

  2. 为什么多个线程不可能同时抢到一把锁_分布式为什么一定要有高可用的分布式锁?看完就知道了...

    分布式锁定义 分布式锁在分布式环境下,锁定全局唯一公共资源,表现为: 请求串行化 互斥性 第一步是上锁的资源目标,是锁定全局唯一公共资源,只有是全局唯一的资源才存在多个线程或服务竞争的情况. 互斥性表 ...

  3. redis锁和分布式锁的实现

    redis环境搭建 redis在java.spring.springboot中的实现 redis锁 1.添加依赖 <dependency><groupId>org.spring ...

  4. 乐观锁、悲观锁、分布式锁的总结

    乐观锁.悲观锁.分布式锁 面试必备-行锁.表锁 - 乐观锁.悲观锁的区别和联系(史上最全)_yxg520s的博客-CSDN博客_行锁和表锁是悲观锁吗 乐观锁.悲观锁.读写锁.互斥锁之间的关系_Leri ...

  5. java mysql 分布式锁_Java分布式锁之数据库方式实现

    之前的文章<Java分布式锁实现>中列举了分布式锁的3种实现方式,分别是基于数据库实现,基于缓存实现和基于zookeeper实现.三种实现方式各有可取之处,本篇文章就详细讲解一下Java分 ...

  6. memcached 分布式锁 java_分布式锁的三种实现方式

    分布式锁的三种实现方式 一.zookeeper 1.实现原理: 基于zookeeper瞬时有序节点实现的分布式锁,其主要逻辑如下(该图来自于IBM网站).大致思想即为:每个客户端对某个功能加锁时,在z ...

  7. 详解线程锁、进程锁、分布式锁以及数据库锁

    线程锁.进程锁.分布式锁以及数据库锁 1. 锁的介绍以及应用: 2. 定时器实现任务生产: 3. 手撕多线程任务队列: 视频讲解如下,点击观看: 线程锁.进程锁.分布式锁以及数据库锁丨C/C++丨Li ...

  8. 详解线程锁、进程锁以及分布式锁,开发过程中解决的具体问题

    聊聊线程锁.进程锁以及分布式锁 1. 线程锁-如何调度消费任务队列的线程池: 2. 进程锁-如何解决nginx惊群问题 3. 分布式锁-如何解决分布式系统中锁竞争问题 [Linux后端开发系列]详解线 ...

  9. 线程锁,进程锁以及分布式锁丨锁的实现及原理分析丨高效的使用

    线程锁.进程锁以及分布式锁 1. 线程锁 2. 进程锁 3. 分布式锁 [技术分享篇]线程锁,进程锁以及分布式锁丨锁的实现及原理分析丨高效的使用 更多精彩内容包括:C/C++,Linux,Nginx, ...

最新文章

  1. notepad++ html格式化
  2. Binary Matrix Transform
  3. 安卓与HTML简单的交互使用
  4. 修改环境变量后,导致一些常用命令失效,如ll,ls,vi不能用
  5. 程序员curd编程是什么_为什么许多程序员讨厌结对编程?
  6. 平面单腿机器人跳跃控制研究——后续内容
  7. 如何以源码安装mysql_CentOS以源码方式安装MySQL
  8. 性能测试——脚本录制1
  9. hdu 二分图最大匹配问题 (hdu 1083)
  10. c语言指向读取的字节数的指针,c - C语言中指针的大小 - SO中文参考 - www.soinside.com...
  11. 【NLP】HuggingFace BERT 微博评论情感分类
  12. 透视分析和即席查询区别
  13. 猜数字游戏(c语言实现)
  14. c r 语言教程,R语言初级教程
  15. MGMT_VIEW 用户的功能与作用
  16. 搭建hexo个人网站小试
  17. tableau高级绘图(十二)-tableau绘制辐射堆叠图
  18. 二值化最佳阈值选取方法以及matlab实现
  19. CICE海冰模式的编译
  20. 【零基础】极星量化入门十一:远程遥控的简单办法

热门文章

  1. 利用数据缓存加速文件备份
  2. 2019年-vSphere 7之ESXi 7.0 RC部署指南(转载)
  3. Java基础学习总结(129)——Arrays.asList得到的List进行add和remove等操作出现异常解析
  4. Linux学习总结(45)——Linux服务器出现卡慢的基本解决方法
  5. Mysql学习总结(19)——Mysql无法创建外键的原因
  6. java ee ssh三大框架知识点_详解JAVAEE——SSH三大框架整合(spring+struts2+hibernate)...
  7. asp.net 性能调较
  8. Mac安装sqlite3
  9. 直接拿来用,10个PHP代码片段
  10. YAML_15 include and roles