佛山网站建设seo优化,做英文的小说网站有哪些,影院wordpress,电商网站建设方案道客巴巴实现分布式锁的方式有多种#xff0c;例如基于数据库、Redis、ZooKeeper 等中间件来实现#xff0c;它们通常依赖于这些中间件提供的事务特性#xff0c;或者命令语义来达到分布式环境下的锁效果。例如#xff0c;Redis 通过 SETNX 命令配合过期时间可实现一个简单的分布式…实现分布式锁的方式有多种例如基于数据库、Redis、ZooKeeper 等中间件来实现它们通常依赖于这些中间件提供的事务特性或者命令语义来达到分布式环境下的锁效果。例如Redis 通过 SETNX 命令配合过期时间可实现一个简单的分布式锁方案。 文章目录 1.SETNX 存在的问题2.Redisson 特性说明3.Redisson 使用分布式锁 1.SETNX 存在的问题
虽然可以使用 SETNX 命令方便的实现分布式锁但是 SETNX 存在以下问题
死锁问题SETNX 如未设置过期时间锁忘记删了或加锁线程宕机都会导致死锁也就是分布式锁一直被占用的情况。锁误删问题SETNX 设置了超时时间但因为执行时间太长所以在超时时间之内锁已经被自动释放了但线程不知道因此在线程执行结束之后会把其他线程的锁误删的问题。不可重入问题也就是说同一线程在已经获取了某个锁的情况下如果再次请求获取该锁则请求会失败因为只有在第一次能加锁成功。也就是说一个线程不能对自己已持有的锁进行重复锁定。无法自动续期线程在持有锁期间任务未能执行完成锁可能会因为超时而自动释放。SETNX 无法自动根据任务的执行情况设置新的超时实现以延长锁的时间。
Redisson 是一个开源的用于操作 Redis 的 Java 框架。与 Jedis 和 Lettuce 等轻量级的 Redis 框架不同它提供了更高级且功能丰富的 Redis 客户端。它提供了许多简化 Redis 操作的高级 API并支持分布式对象、分布式锁、分布式集合等特性。
2.Redisson 特性说明
Redisson 可以设置分布式锁的过期时间从而避免锁一直被占用而导致的死锁问题。Redisson 在为每个锁关联一个线程 ID 和重入次数递增计数器作为分布锁 value 的一部分存储在 Redis 中这样就避免了锁误删和不可重入的问题。Redisson 还提供了自动续期的功能通过定时任务看门狗定期延长锁的有效期确保在业务未完成前锁不会被其他线程获取。
3.Redisson 使用分布式锁
maven:
dependencygroupIdorg.redisson/groupIdartifactIdredisson-spring-boot-starter/artifactIdversion3.25.2/version !-- 请根据实际情况使用最新版本 --
/dependencyCondig:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Configuration
public class RedissonConfig {Beanpublic RedissonClient redissonClient() {Config config new Config();// 也可以将 redis 配置信息保存到配置文件config.useSingleServer().setAddress(redis://127.0.0.1:6379);return Redisson.create(config);}
}Controller:
import org.redisson.api.RLock;
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.RestController;
import java.util.concurrent.TimeUnit;
RestController
public class LockController {Autowiredprivate RedissonClient redissonClient;GetMapping(/lock)public String lockResource() throws InterruptedException {String lockKey myLock;// 获取 RLock 对象RLock lock redissonClient.getLock(lockKey);try {// 尝试获取锁尝试加锁锁超时时间是 30 秒boolean isLocked lock.tryLock(30, TimeUnit.SECONDS);if (isLocked) {// 成功获取到锁try {// 模拟业务处理TimeUnit.SECONDS.sleep(5);return 成功获取锁并执行业务代码;} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.unlock();}} else {// 获取锁失败return 获取锁失败;}} catch (InterruptedException e) {e.printStackTrace();}return 获取锁成功;}
}Redisson 分布式锁的操作和 Java 中的 ReentrantLock可重入锁的操作很像都是先使用 tryLock 尝试获取非公平锁最后再通过 unlock 释放锁。
1.实现公平锁
Redisson 默认创建的分布式锁是非公平锁出于性能的考虑想要把它变成公平锁可使用以下代码实现
RLock lock redissonClient.getFairLock(lockKey); 2.实现读写锁
Redisson 还可以创建读写锁如下代码所示
RReadWriteLock lock redissonClient.getReadWriteLock(lockKey); // 获取读写锁
lock.readLock(); // 读锁
lock.writeLock(); // 写锁读写锁的特点就是并发性能高它是允许多个线程同时获取读锁进行读操作的也就是说在没有写锁的情况下读取操作可以并发执行提高了系统的并行度。但写锁则是独占式的同一时间只有一个线程可以获得写锁无论是读还是写都无法与写锁并存这样就确保了数据修改时的数据一致性。
3.实现联锁
Redisson 也支持联锁也叫分布式多锁 MultiLock它允许客户端一次性获取多个独立资源RLock上的锁这些资源可能是不同的键或同一键的不同锁。当所有指定的锁都被成功获取后才会认为整个操作成功锁定。这样能够确保在分布式环境下进行跨资源的并发控制。联锁的实现示例如下
// 获取需要加锁的资源
RLock lock1 redisson.getLock(lock1);
RLock lock2 redisson.getLock(lock2);
// 联锁
RedissonMultiLock multiLock new RedissonMultiLock(lock1, lock2);
try {// 一次性尝试获取所有锁if (multiLock.tryLock()) {// 获取锁成功...}
} finally {// 释放所有锁multiLock.unlock();
}