但业务场景满足一下三种情况:
- 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现)
- 共享资源(各个系统访问同一个资源,资源的载体可能是传统关系型数据库或者NoSQL)
- 同步访问(即有很多个进程同事访问同一个共享资源)
我们就需要分布式锁来保证不出现并发问题。
RedisLockRegistry和ZookeeperLockRegistry分别利用来redis和zookeeper在分布式项目中的使用来创建分布式锁。
分布式锁是一种悲观锁,需要满足一下特性
1.互斥性:每个线程的创建的锁是互斥的,即A线程创建来锁和B线程创建的锁不能同时锁住。
2.排他性:每个线程的创建的锁是排他的,即当前线程创建的锁只有当前线程能够访问(加锁,解锁)别的线程不允许访问这两者都继承了
package org.springframework.integration.support.locks;
import java.util.concurrent.locks.Lock;
public interface LockRegistry {
Lock obtain(Object var1);
}
1.RedisLockRegistry
需要依赖redis,redis集群在分布式中常用于需要高并发,分区容错,高可用的场景。
redis在分布式锁的使用可参考官方文档:https://redis.io/topics/distlock
spring正是对redis这种特性进行封装。使用redis的策略在大部分高并发的场景中都可以满足。
添加mavan依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
该分布式锁组件获取到的锁为org.springframework.integration.redis.util.RedisLockRegistry.RedisLock。是其内部类
2.ZookeeperLockRegistry
需要依赖zookpeer,zookpeer集群本省满足来分布式场景下的 一致性,分区容错性。
所以ZookeeperLockRegistry在不是特别大的并发下能够完美的保证线程同步。
ZookeeperLockRegistry需要依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-zookeeper</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
该分布式锁组件获取到的锁为org.springframework.integration.zookeeper.lock.ZookeeperLockRegistry.ZkLock。是其内部类
锁的使用:
两种分布式锁都继承来LockRegistry。故可通过LockRegistry来申明变量,获取锁
Lock lock = redisLockRegistry.obtain(lockKey);
try {
log.info("开始争抢锁 ");
if (lock.tryLock(3, TimeUnit.SECONDS)) {
//争抢到锁
log.info("争抢到锁 ");
// do business
}
} catch (Exception e) {
log.error("获取锁失败 : ", e);
} finally {
lock.unlock();
}
lock封装的常用api
void | lock() Acquires the lock. 加锁,如果已经被其他线程锁住或者当前线程不能获取锁则阻塞 |
void | lockInterruptibly() Acquires the lock unless the current thread is interrupted. 加锁,除非当前线程被打断。 |
boolean | tryLock() Acquires the lock only if it is free at the time of invocation. 尝试加锁,如果已经有其他锁锁住,获取当前线程不能加锁,则返回false,加锁失败;加锁成功则返回true |
boolean | tryLock(long time, TimeUnit unit) Acquires the lock if it is free within the given waiting time and the current thread has not been interrupted. 尝试在指定时间内加锁,如果已经有其他锁锁住,获取当前线程不能加锁,则返回false,加锁失败;加锁成功则返回true |
void | unlock() Releases the lock. 解锁 |