IT袋

当前位置:主页 > 经验教程 > 建站编程 >

SpringBoot

SpringBoot Redis分布式锁的正确实现方式(5)

时间:2024-01-24 18:50:11 来源:IT袋 作者:马勇
导读:SpringBoot,加锁 tryLock、lock tryLock 以阻塞等待 waitTime 时间的方式来尝试获取锁。获取成功则返回 true,反之 false。 tryAcquire 方法相当于执行了 Redis 的 SET resourceName u

SpringBoot

加锁 tryLock、lock

tryLock以阻塞等待waitTime时间的方式来尝试获取锁。获取成功则返回 true,反之 false。tryAcquire方法相当于执行了 Redis 的SET resourceName uuid:threadID NX PX {leaseTime}指令。

tryLock不同的是,lock一直尝试自旋阻塞等待获取分布式锁,直到获取成功为止。而tryLock只会阻塞等待waitTime时间。

此外,为了让程序更加健壮,不念实现了阻塞等待获取分布式锁,让你用的更加开心,面试不慌加薪不难。如果你不需要自旋阻塞等待获取锁,那把 while 代码块删除即可。

@Override
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
    long time = unit.toMillis(waitTime);
    long current = System.currentTimeMillis();
    long threadId = Thread.currentThread().getId();
    // 获取锁
    Boolean isAcquire = tryAcquire(leaseTime, unit, threadId);
    // lock acquired
    if (Boolean.TRUE.equals(isAcquire)) {
        return true;
    }
    time -= System.currentTimeMillis() - current;
    // 等待时间用完,获取锁失败
    if (time <= 0) {
        return false;
    }
    // 自旋获取锁
    while (true) {
        long currentTime = System.currentTimeMillis();
        isAcquire = tryAcquire(leaseTime, unit, threadId);
        // lock acquired
        if (Boolean.TRUE.equals(isAcquire)) {
            return true;
        }
        time -= System.currentTimeMillis() - currentTime;
        if (time <= 0) {
            return false;
        }
    }
}
@Override
public void lock(long leaseTime, TimeUnit unit) {
    long threadId = Thread.currentThread().getId();
    Boolean acquired;
    do {
        acquired = tryAcquire(leaseTime, unit, threadId);
    } while (Boolean.TRUE.equals(acquired));
}
private Boolean tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
    return redisTemplate.opsForValue().setIfAbsent(resourceName, getRequestId(threadId), leaseTime, unit);
}

解锁unlock

解锁的逻辑是通过执行 lua 脚本实现。

@Override
public void unlock() {
    long threadId = Thread.currentThread().getId();
    // 执行 lua 脚本
    DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(LuaScript.unlockScript(), Long.class);
    Long opStatus = redisTemplate.execute(redisScript, keys, getRequestId(threadId));
    if (opStatus == null) {
        throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
                + id + " thread-id: " + threadId);
    }
}

LuaScript

其实这个脚本就是在讲解青铜板分布式锁原理的那段代码,具体逻辑已经解释过,这里就不再重复分析。

public class LuaScript {
    private LuaScript() {
    }
    /**
     * 分布式锁解锁脚本
     *
     * @return 当且仅当返回 `1`才表示加锁成功.
     */
    public static String unlockScript() {
        return "if (redis.call('exists', KEYS[1]) == 0) then " +
                "return nil;" +
                "end; "+
                "if redis.call('get',KEYS[1]) == ARGV[1] then" +
                "   return redis.call('del',KEYS[1]);" +
                "else" +
                "   return 0;" +
                "end;";
    }
}

相关阅读

  • b2b推广网站有哪些 垂直b2b电商平台推荐

    b2b推广网站有哪些 垂直b2b电商平台推荐

    跟大家聊一聊b2b推广网站有哪些和垂直b2b电商平台推荐方面的内容,下面小编为您详细解答 最近,很多小伙伴都反馈给我。我想知道哪些B2B网站在市场上做得很好。以下是IT袋网小编收集的全

  • 前端开发工程师是做什么的 web前端的工作内容

    前端开发工程师是做什么的 web前端的工作内容

    IT袋网为大家说一说前端开发工程师是做什么的和web前端的工作内容方面的讲解,请看下面详细的介绍。 随着Internet的发展和多个终端的普及,前端开发工程师逐渐受到欢迎,但是前端开发工程

  • 什么是Ceph 有什么特点?

    什么是Ceph 有什么特点?

    如果想了解什么是CephIT技巧方面的经验,相关内容具体如下: 概述 Ceph是当前非常流行的开源分布式存储系统,具有高扩展性、高性能、高可靠性等优点,同时提供 块存储服务 (rbd)、 对象存储

  • [网络工程师]-网络规划与设计-通信规范分析

    [网络工程师]-网络规划与设计-通信规范分析

    相对于大多数人[网络工程师]-网络规划与设计-通信规范分析方面的介绍,下面为详细的介绍。 在网络分析和设计过程中,通信规范分析处于第二个阶段,通过分析网络通信流量和通信模式,发