当前位置: 首页 > news >正文

分布式锁方案-Redisson

分布式锁:Redisson还实现了Redis文档中提到像分布式锁Lock这样的更高阶应用场景。事实上Redisson并没有不止步于此,在分布式锁的基础上还提供了联锁(MultiLock),读写锁(ReadWriteLock),公平锁(Fair Lock),红锁(RedLock),信号量(Semaphore),可过期性信号量(PermitExpirableSemaphore)和闭锁(CountDownLatch)这些实际当中对多线程高并发应用至关重要的基本部件。正是通过实现基于Redis的高阶应用方案,使Redisson成为构建分布式系统的重要工具。

依赖

<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.15.5</version>
</dependency>

样例

	@Autowired
	RedissonClient redissonClient;
	
	
	public String TestLock() {
	    // 1.获取锁,只要锁的名字一样,获取到的锁就是同一把锁。
	    RLock lock = redisson.getLock("redisson-lock");
	
	    // 2.加锁
	    lock.lock();
	    try {
	        System.out.println("加锁成功,执行后续代码。线程 ID:" + Thread.currentThread().getId());
	        Thread.sleep(10000);
	    } catch (Exception e) {
	        //TODO
	    } finally {
	        lock.unlock();
	        // 3.解锁
	        System.out.println("Finally,释放锁成功。线程 ID:" + Thread.currentThread().getId());
	    }
	
	    return "test lock ok";
	}

锁无过期时间情况:服务停了,锁会释放-看门狗原理

如果负责储存这个分布式锁的 Redisson 节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。

默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

如果我们未制定 lock 的超时时间,就使用 30 秒作为看门狗的默认时间。只要占锁成功,就会启动一个定时任务:每隔 10 秒重新给锁设置过期的时间,过期时间为 30 秒。

设置锁过期时间

RLock lock = redissonClient.getLock("lock-expireTime");
lock.lock(10000, java.util.concurrent.TimeUnit.MILLISECONDS);

不使用此框架的情况下

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RedisTemplateDistributedLock {

    private RedisTemplate<String, Object> redisTemplate;

    public RedisTemplateDistributedLock(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
        // 设置序列化器,避免乱码问题
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
    }

    /**
     * 获取分布式锁
     * @param lockKey 锁的键
     * @param expireTime 锁的过期时间
     * @param timeUnit 时间单位
     * @return 锁的唯一标识,如果获取失败返回 null
     */
    public String tryLock(String lockKey, long expireTime, TimeUnit timeUnit) {
        String requestId = UUID.randomUUID().toString();
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, timeUnit);
        return result != null && result ? requestId : null;
    }

    /**
     * 释放分布式锁
     * @param lockKey 锁的键
     * @param requestId 锁的唯一标识
     * @return 是否成功释放锁
     */
    public boolean releaseLock(String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId);
        return result != null && result == 1;
    }
}    
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

public class RedisTemplateDistributedLockUsage {
    public static void main(String[] args) {
        // 假设这里已经有 RedisConnectionFactory 的实例
        RedisConnectionFactory redisConnectionFactory = null;
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();

        RedisTemplateDistributedLock lock = new RedisTemplateDistributedLock(redisTemplate);
        String lockKey = "myDistributedLock";
        long expireTime = 10;
        TimeUnit timeUnit = TimeUnit.SECONDS;

        // 尝试获取锁
        String requestId = lock.tryLock(lockKey, expireTime, timeUnit);
        if (requestId != null) {
            try {
                System.out.println("成功获取到锁,开始执行临界区代码");
                // 模拟业务操作
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                // 释放锁
                boolean released = lock.releaseLock(lockKey, requestId);
                if (released) {
                    System.out.println("锁已成功释放");
                } else {
                    System.out.println("锁释放失败");
                }
            }
        } else {
            System.out.println("未能获取到锁");
        }
    }
}    
http://www.dtcms.com/a/107254.html

相关文章:

  • Linux命令-tar
  • 使用 MapReduce 进行高效数据清洗:从理论到实践
  • Linux内核中ARP协议的实现与dev_addr字段的作用
  • LabVIEW 调用 Python 函数
  • SAP-ABAP:ABAP `LEAVE LIST-PROCESSING` 深度解析
  • 天梯赛 L2-023 图着色问题
  • ai prompt工程师认证
  • AT_abc306_b [ABC306B] Base 2
  • 【工具变量】全国分省低空经济高质量发展数据(2012-2023年)
  • Word 插入无页眉页码的空白页(即插入奇数页)
  • WebSocket connection failed 解决
  • 基于机器学习的三国时期诸葛亮北伐失败因素量化分析
  • 数学知识集锦
  • Ubuntu24.04-中文输入法的切换
  • 批量将文本文件转换为 Word/PDF/Excel/图片等其它格式
  • python-leetcode 64.在排序数组中查找元素的第一个和最后一个位置
  • c语言大小端判断
  • 【JavaScript】十三、事件监听与事件类型
  • 95. 费解的开关
  • 密码学基础——古典密码学
  • 云端革命:数字文明的重构与新生
  • int main(int argc, char **argv)C语言主函数参数解析
  • 【AI News | 20250402】每日AI进展
  • JavaScript基础-移动端常见特效
  • 代码训练营day22
  • leetcode 62. Unique Paths
  • Npfs!NpFsdWrite函数和Npfs!NpCommonWrite函数和Npfs!NpWriteDataQueue函数中的DeferredList
  • Python运算符的理解及简单运用
  • 《数字图像处理》教材寻找合作者
  • 【Java NIO】