Redisson分布式锁入门使用记录

使用场景

日常开发场景中在redis做缓存的时候,有一个必须要考虑的问题,就是数据库内容和redis库里应该保持一致(双写一致性),要不然就会有脏数据或者其他的问题。

解决方案

解决方案一般有两个大方向,

1.系统追求强一致性,那就需要加锁,可以使用今天这篇文章讲解的Redission的读写锁。

2.不太注重强一致性的话,数据可以有一定的延时(符合大部分系统使用情况),可以使用延时双删,canal组件,mq传输等等方案。

今天就写了个Redission分布式锁的入门使用记录。

步骤

一、Redisson读写锁

先有写锁时,不会立刻给数据加读锁,需要等写锁释放后,才能加读锁。
先有读锁时,写锁也需要等待读锁的释放,才能加写锁。
同时访问读锁时,会同时加锁成功,相当不加锁并发读数据。
只要有写锁的存在,都必须等待,写锁是一个排它锁,只能有一个写锁存在,读锁是一个共享锁,可以有多个读锁同时存在。

二、示例代码

1. 引入 Maven 依赖

引入redission的依赖。

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.8.2</version>
        </dependency>

2. 配置application.yml文件连接到redis

  redis:
    host: 192.168.22.88
    port: 6379
    timeout: 86400
    password: 123456
    jedis:
      pool:
        max-active: 8
        max-wait: 10000
        max-idle: 8
        min-idle: 0
        time-between-eviction-runs: 1000

3. 编写RestController测试类TestMyLock

package com.redissondemo.controller;
 
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * 2022年7月30日23:27:20
 */
@RestController
@RequestMapping(path = "/mylock")
public class TestMyLock {
 
    @Autowired
    private RedissonClient redisson;
 
    /**
     * 写锁,变更图书信息
     * 2022年8月13日15:56:42
     * @param bookId
     * @return
     */
    @GetMapping("/upBook")
    public String updateBook(Long bookId){
        if(bookId == null || bookId<=0){
            return "error";
        }
        //图书ID做为锁名称
        String lockkey=bookId.toString();
        //获取读写锁
        RReadWriteLock lock = redisson.getReadWriteLock(lockkey);
        System.out.println("获得:writeLock---getReadWriteLock====");
        //获得写锁
        RLock rLock = lock.writeLock();
        System.out.println("获得:writeLock---");
        //加锁
        rLock.lock();
        try {
            System.out.println("lock()加锁成功,更新图书信息--------Thread.sleep(10000)---------线程ID" + Thread.currentThread().getId());
            Thread.sleep(10000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //解锁
            rLock.unlock();
            System.out.println("更新图书信息完毕,finally解锁-----------------线程ID" + Thread.currentThread().getId());
        }
        return "book更新成功!...";
    }
 
    /**
     * 读锁,读取图书信息
     * 2022年8月13日15:57:11
     * @param bookId
     * @return
     */
    @GetMapping("getBook")
    public String getBook(Long bookId){
        if(bookId == null || bookId<=0){
            return "error";
        }
        //图书ID做为锁名称
        String lockkey=bookId.toString();
        //获取读写锁
        RReadWriteLock lock = redisson.getReadWriteLock(lockkey);
        System.out.println("获得:readLock---读锁----.......getReadWriteLock********");
        //获得读锁
        RLock rLock = lock.readLock();
        System.out.println("获得:readLock---读锁----.......");
        //加锁
        rLock.lock();
        try {
            System.out.println("lock()加锁成功,读取图书-..........-----==Thread.sleep(6000)==========线程ID" + Thread.currentThread().getId());
            Thread.sleep(6000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
            System.out.println("读取图书完毕!------finally解锁===-线程ID" + Thread.currentThread().getId());
        }
        return "BOOK...读取成功!。。。。。。";
    }
 
}

三、启动项目测试

复制工程到两个不同目录,分别启动服务端口8080和8081的两个实例。(注意启动redis服务)

(1)先访问:127.0.0.1:8080/mylock/upBook?bookId=1(写锁)
再访问:127.0.0.1:8080/mylock/getBook?bookId=1(读锁)

如上图运行结果可以看出:写锁存在时,读锁需要等待写锁释放后才能加锁执行。 

(2)先访问:127.0.0.1:8080/mylock/getBook?bookId=1(读锁) 
再访问:127.0.0.1:8080/mylock/upBook?bookId=1(写锁)

如上图运行结果可以看出:读锁存在时,写锁需要等待读锁释放后才能加锁执行。

(3)先访问:127.0.0.1:8080/mylock/upBook?bookId=1(写锁)
再访问:127.0.0.1:8080/mylock/getBook?bookId=1(读锁)和127.0.0.1:8081/mylock/getBook?bookId=1

 

如上图运行结果(第一个图8080服务实例,第二个图8081服务实例):先访问一个写锁,在几乎同时访问两个读锁,两个读锁都在写锁释放后几乎同时加锁成功执行。说明:多个读锁代码可以并发执行,是一个共享锁。

(4)先访问:127.0.0.1:8080/mylock/upBook?bookId=1(写锁)
再访问:127.0.0.1:8080/mylock/upBook?bookId=1(写锁)

如上图运行结果:82线程的写锁释放后,83线程的写锁才加锁成功执行。说明:写锁互斥,是一个排它锁。需要等待上一个锁释放。 

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Redisson是一个基于Redis实现的Java驻内存数据网格(In-Memory Data Grid)和分布式锁(Distributed Lock)框架,它提供了一系列的分布式数据结构,其中包括分布式锁的实现。 使用Redisson实现分布式锁非常简单,只需要遵循以下步骤: 1. 引入Redisson的依赖包: ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.6</version> </dependency> ``` 2. 创建Redisson客户端对象: ```java Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` 3. 获取锁对象: ```java RLock lock = redisson.getLock("myLock"); ``` 4. 加锁: ```java lock.lock(); ``` 5. 执行业务逻辑: ```java try { // 执行业务逻辑 } finally { // 释放锁 lock.unlock(); } ``` 完整的示例代码如下: ```java public class MyService { private RedissonClient redisson; public MyService() { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); redisson = Redisson.create(config); } public void myMethod() { RLock lock = redisson.getLock("myLock"); try { lock.lock(); // 执行业务逻辑 } finally { lock.unlock(); } } } ``` 需要注意的是,在执行业务逻辑的过程中,一定要放在try...finally块中,并在finally块中释放锁,以确保在出现异常时锁能够正确地被释放。 ### 回答2: Redisson是一种基于Redis实现的分布式锁框架。以下是Redisson分布式锁使用说明: 1. 引入Redisson依赖:首先需要在项目中引入Redisson的依赖,可以通过Maven或者Gradle等构建工具来管理依赖。 2. 创建RedissonClient:使用RedissonClient可以连接到Redis服务器,并获取一个分布式锁对象。 3. 加锁使用分布式锁对象可以通过lock()方法来获取锁,该方法默认的锁超时时间是30秒,超过该时间锁会自动释放。也可以使用自定义的锁超时时间。 4. 解锁:在加锁的代码块执行完毕后,需要调用unlock()方法手动释放锁,确保锁的释放,避免死锁的产生。 5. 锁的可重入性:Redisson分布式锁支持可重入性,即同一个线程可以多次获取同一个锁,在释放锁的时候需要调用相应次数的unlock()方法来释放锁。 6. 锁的异步执行:Redisson分布式锁也支持异步执行,即lock()方法可以通过异步方式获取锁。 7. 锁的公平性:Redisson分布式锁可以选择是否公平锁,默认为非公平锁,即不保障获取锁的顺序。可以通过配置参数来设置公平锁。 8. 锁监控:Redisson提供了监控分布式锁的功能,可以通过调用getLock("/lock")方法来监控名为"lock"的锁的情况。 总结来说,Redisson分布式锁使用非常简单,只需要引入依赖、创建客户端、加锁和解锁即可。同时,Redisson还提供了可重入性、异步执行、公平锁和锁监控等功能,可以根据实际需求进行配置和使用。通过使用Redisson分布式锁,可以有效地控制多线程环境下共享资源的访问,避免数据不一致和竞态条件的发生。 ### 回答3: Redisson是一个基于Redis的Java实现,提供了一系列分布式相关的功能,其中包括分布式锁使用使用Redisson实现分布式锁,首先需要创建一个RedissonClient实例,通过该实例可以获取一个RLock对象,RLock提供了加锁和释放锁的方法。 在加锁方面,Redisson支持公平锁和非公平锁。公平锁会按照请求的顺序依次加锁,而非公平锁则允许插队,谁先抢到锁就谁先执行。通过调用RLock对象的lock()方法可以获取锁,该方法会一直阻塞直到获取到锁为止。如果不希望一直阻塞,可以使用tryLock()方法,该方法会尝试获取锁一段时间,如果超过指定的等待时间仍未获取到锁,则返回false。 在释放锁方面,可以使用unlock()方法来释放锁,只有加锁方才能释放锁。可以通过判断当前线程是否持有锁,再决定是否释放锁。 使用Redisson分布式锁还有一些其他的特性,比如锁的自动续约、可重入锁、可中断锁等,这些特性都可以通过相应的方法来使用。 总的来说,Redisson分布式锁使用起来非常方便,只需要简单的几行代码就可以实现分布式环境下的锁功能。但需要注意的是,在使用分布式锁时要考虑并发情况、死锁问题以及锁的粒度等,以确保代码的正确性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值