文章目录
前言
参考文章:
分布式锁的几种简单实现方式分析_基于缓存实现分布式锁的实现方式有-优快云博客
提示:以下是本篇文章正文内容,下面案例可供参考
一、Redis缓存是什么?
高性能--高并发
- Redis是一个内存数据库,通过将数据存储在内存中而非磁盘,能够实现极快的读写速度。
- Redis使用数据结构,如字符串、哈希、列表等,以便快速访问所需数据,通常用键值对<key,value>来表示。
- Redis采用单线程模型,避免了多线程竞争带来的复杂性,从而进一步提高了性能。
- Redis 除了做缓存之外,也经常用来做分布式锁,消息队列。
二、实现过程
1.思路
在Redis中,可以使用
SETNX
命令来实现基本的分布式锁。SETNX
命令会尝试在缓存中设置一个键值对,如果键不存在,则设置成功并返回1;如果键已存在,则设置失败并返回0。还需要考虑:
- 缓存的持久性: 确保锁在系统重启或缓存失效时能够正确恢复。
- 缓存的过期时间: 可以为锁设置了一个过期时间,以防止节点在获取锁后崩溃或异常退出,导致锁一直无法释放。设置合理的过期时间可以避免锁长时间占用而导致的资源浪费。
- 锁的安全释放:在使用Redis的DEL命令来删除锁时,需要确保操作的原子性,避免误删其他节点持有的锁,避免造成多线程或多节点情况下的并发问题。我们可以引入一个计数器,记录某个线程获取锁的次数。当线程再次尝试获取锁时,只有计数器为0时才会真正获取锁,否则只会增加计数器。释放锁时,计数器减少,直到为0才真正释放锁。
- 缓存的一致性:在使用多个缓存节点时,确保它们之间存储的数据保持一致性。由于缓存可能会存储临时数据,因此在多个节点同时访问和修改数据时,保持数据的准确性和一致性变得尤为重要。可以选择使用Redis的集群模式或者使用分布式锁库,确保锁在多个节点间的一致性。
2.代码
代码如下(示例):
public class DistributedLockForRedis {
private static final String REDIS_HOST = "localhost";
private static final int REDIS_PORT = 6379;
// 获取锁
public static boolean acquireLock(String lockName, int timeout) {
Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);
long startTime = System.currentTimeMillis();
while (true) {
//Redis命令解释:NX:表示如果锁不存在则设置成功。EX:表示设置锁的过期时间为timeout秒。
String result = jedis.set(lockName, "holder", "NX", "EX", timeout);
if (result != null && result.equalsIgnoreCase("OK")) {
// 成功获取到锁
return true;
} else if (System.currentTimeMillis() - startTime > timeout) {
// 超时退出
return false;
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// 线程被中断
Thread.currentThread().interrupt();
}
}
}
}
// 释放锁
public static void releaseLock(String lockName) {
Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);
jedis.del(lockName);
}
// 使用锁
public static void doSomethingWithLock() {
String lockName = "my_lock";
if (acquireLock(lockName, 5000)) {
try {
// 执行需要加锁的操作
System.out.println("Lock acquired. Doing something...");
Thread.sleep(5000);
System.out.println("Finished.");
} catch (InterruptedException e) {
// 线程被中断
Thread.currentThread().interrupt();
} finally {
releaseLock(lockName);
}
} else {
System.out.println("Failed to acquire lock.");
}
}
// 主程序
public static void main(String[] args) {
doSomethingWithLock();
}
}