1.上篇讲了java里使用setNX实现redis分布式锁,可是这种方法还是有很多弊端的,追求完美的做法可以使用redisson来实现分布式锁,如下:

2.Redisson 是 java 的 Redis 客户端之一,是 Redis 官网推荐的 java 语言实现分布式锁的项目。

它提供了一些 api 方便操作 Redis。因为本文主要以锁为主,所以接下来我们主要关注锁相关的类,以下是 Redisson 中提供的多样化的锁:

可重入锁(Reentrant Lock)公平锁(Fair Lock)联锁(MultiLock)红锁(RedLock)读写锁(ReadWriteLock)信号量(Semaphore)

3.本文中 Redisson 分布式锁的实现是基于 RLock 接口,而 RLock 锁接口实现源码主要是 RedissonLock 这个类,而源码中加锁、释放锁等操作都是使用 Lua 脚本来完成的,并且封装的非常完善,开箱即用。

接下来主要以 Redisson 实现 RLock (用的最多)可重入锁为主。

4.Maven 依赖 pom.xml,Redisson、MySQL 等相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>redis-redlock</artifactId><version>0.0.1-SNAPSHOT</version><name>redis-redlock</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency><!-- redisson --><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.11.1</version></dependency><!-- Gson --><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version></dependency><!-- Mysql Connector --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.48</version></dependency><!-- 数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.20</version></dependency><!-- Hutool工具包 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>4.6.8</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

5.application.yml 配置文件

server:port: 8888servlet:context-path: /spring:# 数据源datasource:url: jdbc:mysql://127.0.0.1:3306/redisson_demo?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: xxxxpassword: xxxxtype: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.jdbc.DriverlogSlowSql: trueredis:password: xxxxclusters: 10.211.55.4:6379, 10.211.55.4:6380, 10.211.55.4:6381lettuce:pool:min-idle: 0max-idle: 8max-active: 20# 日志
logging:# 输出级别level:root: infofile:# 指定路径path: redis-logs# 最大保存天数max-history: 7# 每个文件最大大小max-size: 5MB

6.Redisson配置类

import java.io.IOException;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** redisson配置*/
@Configuration
public class RedissonManager {@Value("${spring.redis.clusters}")private  String cluster;@Value("${spring.redis.password}")private String password;@Beanpublic RedissonClient getRedisson(){String[] nodes = cluster.split(",");//redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加List<String> collect = Stream.of(nodes).map(x->"redis://"+x).collect(Collectors.toList());Config config = new Config();config.setThread(4);config.setNettyThreads(4);config.useClusterServers() //这是用的集群server.setScanInterval(2000) //设置集群状态扫描时间 .addNodeAddress(collect).setPassword(password);//可通过打印redisson.getConfig().toJSON().toString()来检测是否配置成功return Redisson.create(config);}}

7.加锁实现

@Slf4j
@Service
@Transactional
public class OrderServerImpl implements OrderServer {@Resourceprivate RedissonClient redissonClient;@Override@Transactional(rollbackFor = Exception.class)public boolean createOrder(String userId, String productId) {/**  加锁 **/RLock lock = redissonClient.getLock("stock:" + productId);try {if(!lock.tryLock(10,30, TimeUnit.SECONDS)){throw new RuntimeException("获取锁失败");}/** 减库存操作 **/return true;} catch (Exception ex) {log.error("下单失败", ex);} finally {if(lock.isHeldByCurrentThread()){lock.unlock();}}return false;}
}

8.lock() 方法

RLock lock = redissonClient.getLock("xxx");/*最常见的使用方法*/
lock.lock();/*支持过期解锁,30秒之后自动释放锁,无须调用unlock方法手动解锁*/
lock.lock(30, TimeUnit.SECONDS);

9.tryLock() 方法

RLock lock = redissonClient.getLock("xxx");/*尝试加锁,最多等待10秒,上锁以后10秒自动解锁,返回true表示加锁成功*/
if(lock.tryLock(10,10, TimeUnit.SECONDS)){xxx
}

10.RedLock 中的方法

RLock 本身继承自 Lock 接口,如下分为两部分展示:

public interface RLock extends Lock, RLockAsync {//----------------------Lock接口方法-----------------------/*** 加锁 锁的有效期默认30秒*/void lock();/*** tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false .*/boolean tryLock();/*** tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,* 在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。** @param time 等待时间* @param unit 时间单位 小时、分、秒、毫秒等*/boolean tryLock(long time, TimeUnit unit) throws InterruptedException;/*** 解锁*/void unlock();/*** 中断锁 表示该锁可以被中断 假如A和B同时调这个方法,A获取锁,B为获取锁,那么B线程可以通过* Thread.currentThread().interrupt(); 方法真正中断该线程*/void lockInterruptibly();//----------------------RLock接口方法-----------------------/*** 加锁 上面是默认30秒这里可以手动设置锁的有效时间** @param leaseTime 锁有效时间* @param unit      时间单位 小时、分、秒、毫秒等*/void lock(long leaseTime, TimeUnit unit);/*** 这里比上面多一个参数,多添加一个锁的有效时间** @param waitTime  等待时间* @param leaseTime 锁有效时间* @param unit      时间单位 小时、分、秒、毫秒等*/boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;/*** 检验该锁是否被线程使用,如果被使用返回True*/boolean isLocked();/*** 检查当前线程是否获得此锁(这个和上面的区别就是该方法可以判断是否当前线程获得此锁,而不是此锁是否被线程占有)* 这个比上面那个实用*/boolean isHeldByCurrentThread();/*** 中断锁 和上面中断锁差不多,只是这里如果获得锁成功,添加锁的有效时间* @param leaseTime  锁有效时间* @param unit       时间单位 小时、分、秒、毫秒等*/void lockInterruptibly(long leaseTime, TimeUnit unit);
}

下一篇锁续期

redis分布式锁之redisson可重入锁相关推荐

  1. 可重入锁-synchronized是可重入锁吗?

    目录 前言 1.什么是可重入锁呢? 2.自己写代码验证下可重入和不可重入 3.自己如何实现一个可重入和不可重入锁呢 4.ReentrantLock如何实现可重入的 5.可重入锁的特点 前言 面试题:s ...

  2. 可重入锁与非可重入锁

    文章目录 锁的分类 什么是可重入锁 测试lock 锁的可重入性 不可重入锁 锁的分类 什么是可重入锁 可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前 ...

  3. java 并发锁_Java并发教程–重入锁

    java 并发锁 Java的synced关键字是一个很棒的工具–它使我们可以通过一种简单可靠的方式来同步对关键部分的访问,而且也不难理解. 但是有时我们需要对同步进行更多控制. 我们要么需要分别控制访 ...

  4. java重入锁,再探JAVA重入锁

    之前的文章中简单的为大家介绍了重入锁JAVA并发之多线程基础(2).这里面也是简单的为大家介绍了重入锁的几种性质,这里我们就去探索下里面是如何实现的. 我们知道在使用的时候,必须锁先有定义,然后我们再 ...

  5. java 线程的可重入锁_java 多线程-可重入锁

    可重入锁:锁可以连续使用 计数器+判断进入的线程是不是已经锁定的线程,如果是那就不用等待,直接使用 public class my { public static void main(String[] ...

  6. 锁-概念:可重入锁、可中断锁、公平锁、读写锁

    可重入锁 指的是在同一个thread中,获取锁之后再次使用同样的方法或对象中的其他方法可以直接操作,而不需要重新获取锁.它是基于thread粒度的,per-thread. 不可重入锁 指的是每次使用锁 ...

  7. java dom4j读写锁,java锁的深度化-重入锁,读写锁,乐观锁,悲观锁

    1.重入锁 目的:避免死锁的现象 锁作为并发共享数据,保证一致性的工具,在java平台有多种实现synchronized(重量级)和ReentrantLock(轻量级)等等,这些已经写好提供的锁为我们 ...

  8. 什么是可重入锁?为什么需要可重入锁?

    可重入锁,从字面来理解,就是可以重复进入的锁. 可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响. 在JAVA环境下ReentrantLock和s ...

  9. Redis核心数据结构List应用场景-商品列表、缓存击穿、PV阅读量、抢红包、推送帖子、普通分布式锁、Redis可重入锁与红锁

    List应用场景 Redis之List 一. Redis list命令实战 二.商品列表 高并发的淘宝聚划算实现技术方案 SpringBoot+Redis实现商品列表功能 二.缓存击穿 什么是缓存击穿 ...

最新文章

  1. linux下ntp服务器搭建方法
  2. Task Runner Explorer for vs2015找不到啊
  3. AD19 add pins to nets错误_《英雄联盟手游》错误代码问题大全 LOL的错误代码都是什么意思...
  4. 2020年5月十大热门报告盘点(附下载链接)
  5. JAVA:DOM解析XML和修改XML
  6. Qt引用Boost问题
  7. getAttribute、setAttribute、removeAttribute
  8. Red Hat 5.6-64位使用yum升级PHP
  9. 解决安卓GridView的横向滚动问题
  10. php5apache2.dll,Apache2.2.8 + PHP5.2.5不能加载php5apache2.dll
  11. 2022官网下载jdk8教程
  12. 什么是DNS Spoofing, DNS Hijacking, and DNS Cache Poisoning?
  13. 跟踪fork: Resource temporarily unavailable的原因
  14. 【.Net平台下插件开发】-MEF与MAF初步调研
  15. Designing Specification
  16. 微信小程序仿打卡小程序
  17. 钱包:BUMO 小布口袋 APP 用户手册
  18. 【2016浴雨沐风】(第一篇)
  19. 语义分割代码实现细节:CE_Loss 和 BCE_loss
  20. C语言运算符逻辑运算符位运算符

热门文章

  1. 一屋不扫何以扫天下?
  2. Springboot 集成积木报表(jimuReport)
  3. 水果店如何处理损耗,水果店的损耗控制
  4. Deepin20Beta启用网卡远程开机/唤醒功能Wake-on-LAN(WOL)并保持开启状态
  5. Mybatis中selectKey 标签的作用,主键回填,找了好多文章没一个解释清楚。。
  6. 关于IE9卸载的解决方案
  7. SOCKET函数详解
  8. 郑州美食大集合(不断更新)
  9. C++Qt开发——音视频播放
  10. Python-Django毕业设计天津市杨柳青智慧景区信息系统(程序+LW)