단일 머신 멀티스레딩: Java에서는 일반적으로 ReetrantLock 클래스 및 동기화 키워드와 같은 로컬 잠금을 사용하여 JVM 프로세스의 여러 스레드가 로컬 공유 리소스에 액세스하는 것을 제어합니다
분산 시스템: 다양한 서비스/클라이언트가 일반적으로 독립적인 JVM 프로세스에서 실행됩니다. 여러 JVM 프로세스가 동일한 리소스를 공유하는 경우 로컬 잠금을 사용하여 리소스에 상호 배타적으로 액세스할 수 있는 방법이 없습니다. 따라서 분산 잠금이 탄생했습니다.
예: 총 3개의 시스템 주문 서비스 사본이 배포되었으며, 모두 외부 세계에 서비스를 제공합니다. 사용자는 주문을 하기 전에 재고를 확인해야 합니다. 과잉 판매를 방지하려면 재고 확인 작업에 대한 동기 액세스를 달성하기 위한 잠금이 필요합니다. 주문 서비스가 다른 JVM 프로세스에 있으므로 이 경우 로컬 잠금이 제대로 작동하지 않습니다. 여러 스레드가 동일한 JVM 프로세스에 있지 않더라도 동일한 잠금을 획득하여 공유 리소스에 대한 상호 배타적 액세스를 달성할 수 있도록 분산 잠금을 사용해야 합니다.
가장 기본적인 분산 잠금 요구 사항:
상호 배제: 언제든지 하나의 스레드에서만 잠금을 유지할 수 있습니다.
고가용성: 잠금 서비스의 가용성이 높습니다. 또한 잠금을 해제하기 위한 클라이언트의 코드 논리에 문제가 있더라도 잠금은 결국 해제되며 공유 리소스에 대한 다른 스레드의 액세스에는 영향을 미치지 않습니다.
재진입자: 노드가 잠금을 획득한 후 다시 잠금을 획득할 수 있습니다.
로컬 잠금이든 분산 잠금이든 핵심은 == "상호 배제"에 있습니다 = =.
Redis에서는 SETNX
命令是可以帮助我们实现互斥。SETNX
가 존재하지 않는 경우 SET입니다(Java의 setIfAbsent 메서드에 해당). 키가 없으면 키 값이 설정됩니다. 키가 이미 존재하는 경우 SETNX는 아무 작업도 수행하지 않습니다.
> SETNX lockKey UniqueValue
(integer) 1
> SETNX lockKey UniqueValue
(integer) 0
잠금을 해제하려면 DEL 명령
실수로 다른 잠금을 삭제하는 것을 방지하기 위해 여기서는 Lua 스크립트를 사용하여 키에 해당하는 값(고유 값)으로 판단하는 것이 좋습니다. Lua 스크립트는 잠금 해제 작업의 원자성을 보장하기 위해 선택되었습니다. Redis는 Lua 스크립트를 원자적 방식으로 실행할 수 있으므로 잠금 해제 작업의 원자성을 보장합니다.> 정수) 1
// 释放锁时,先比较锁对应的 value 值是否相等,避免锁的误释放 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end이것은 가장 간단한 Redis 분산 잠금 구현입니다. 구현 방법이 비교적 간단하고 성능이 매우 효율적입니다. 그러나 이러한 방식으로 분산 잠금을 구현하는 데에는 몇 가지 문제가 있습니다. 예를 들어, 잠금 해제 논리가 갑자기 중단되는 등 애플리케이션에 몇 가지 문제가 발생하면 잠금이 해제되지 않을 수 있으며 다른 스레드/프로세스에서 더 이상 공유 리소스에 액세스할 수 없습니다. 2. 잠금에 만료 시간을 설정하는 이유주로 잠금이 해제되는 것을 방지하기 위한 것입니다
127.0.0.1:6379> SET lockKey UniqueValue EX 3 NXOK
使用方式举例:
// 1.获取指定的分布式锁对象
RLock lock = redisson.getLock("lock");
// 2.拿锁且不设置锁超时时间,具备 Watch Dog 自动续期机制
lock.lock();
// 3.执行业务
...
// 4.释放锁
lock.unlock();
只有未指定锁超时时间,才会使用到 Watch Dog 自动续期机制。
// 手动给锁设置过期时间,不具备 Watch Dog 自动续期机制 lock.lock(10, TimeUnit.SECONDS);
总的来说就是使用Redisson,它带有自动的续期机制
所谓可重入锁指的是在一个线程中可以多次获取同一把锁,比如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法即可重入 ,而无需重新获得锁。像 Java 中的 synchronized 和 ReentrantLock 都属于可重入锁。
可重入分布式锁的实现核心思路是线程在获取锁的时候判断是否为自己的锁,如果是的话,就不用再重新获取了。为此,我们可以为每个锁关联一个可重入计数器和一个占有它的线程。当可重入计数器大于 0 时,则锁被占有,需要判断占有该锁的线程和请求获取锁的线程是否为同一个。
위 내용은 Java 분산 잠금을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!