Redis之分布式锁实现

    技术2026-01-29  9

    1、分布式锁:

    1)本质上要实现的目标就是在redis里面占一个位置,当别的进程也要来占用时,发现该位置已经被占用了,只好放弃接下来的操作或稍后重试。 2)占坑执行完逻辑后,再进行释放,但是有个问题,如果逻辑执行到中间遇到异常,可能导致坑未被释放,这样就会陷入死锁,永远得不到释放。于是,我们可以在加锁时设置一个过期时间,让其到期自动释放。

    2、实战:

    现在我们用多线程模拟多个实例抢锁的情况。(在单测中,主线程结束后会强制退出所有线程,故使用CountDownLatch等待子线程执行完毕。)

    @Test public void distributedLock() throws InterruptedException { ExecutorService pool = Executors.newFixedThreadPool(5); CountDownLatch latch = new CountDownLatch(5); IntStream.range(0, 5).forEach(i -> { pool.execute(() -> { Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("test", "lock", 5, TimeUnit.SECONDS); if (aBoolean) { System.out.println(Thread.currentThread().getId() + "--" + Thread.currentThread().getName() + ":抢锁成功!"); } else { System.out.println(Thread.currentThread().getId() + "--" + Thread.currentThread().getName() + ":抢锁失败!"); } latch.countDown(); }); }); latch.await(); }

    可以看到执行结果中只有一个线程抢占成功,抢到后便可以执行后续逻辑。 可用于多实例部署时,定时任务逻辑的执行。或者将一个大任务分配给部署的各个实例,每个处理一部分,提高效率。 (latch.countDown()最好在finally语句块内执行。)

    3、上述方案风险:

    在集群中,当主节点挂掉时,从节点会取而代之,但客户端却没有明显感知。原先一个客户端在主节点申请成功了一把锁,但是这把锁还没有来得及同步到从节点,主节点突然挂了,从节点变成主节点后,内部没有这个锁,则当另一个客户端请求加锁时,立即就批准了,不安全性由此产生。 为了解决这个问题,可以使用Redlock算法,向过半节点发送指令,只要过半节点设置成功,则认为加锁成功。

    Processed: 0.013, SQL: 9