- 相对于使用redis,用zk实现分布式锁有着天生的优势,具体的原因之后有机会再记录,直接进入如何使用。
- 构建InterProcessLock
@Bean
public InterProcessLock interProcessLock() {
CuratorFramework curatorFramework = getZkClient(host);
curatorFramework.start();
InterProcessLock interProcessLock = new InterProcessMutex(curatorFramework,
zkPathEnvironment);
return interProcessLock;
}
- 此处使用InterProcessLock的InterProcessMutex可重入锁实现。
- 业务逻辑加锁
public void syncMemberFromGitlabJob() throws Exception {
System.out.println("=======================定时同步任务开始=======================");
//加锁
if(!interProcessLock.acquire(1, TimeUnit.MILLISECONDS)){
throw new RuntimeException("排他锁获取失败");
}
System.out.println("=======================同步任务加zk锁成功=======================");
try {
//逻辑
Thread.sleep(20000);
System.out.println("=======================定时同步任务完成=======================");
}catch (Exception e){
System.out.println("=======================同步时出现错误,错误为:" + e.getMessage());
}finally {
//释放锁
interProcessLock.release();
System.out.println("=======================同步任务释放zk锁成功=======================");
}
}
- 执行中使用interProcessLock.acquire()尝试上锁,acquire()有两种构建方法,源码为:
/**
* Acquire the mutex - blocking until it's available. Each call to acquire must be balanced by a call
* to {@link #release()}
*
* @throws Exception ZK errors, connection interruptions
*/
public void acquire() throws Exception;
/**
* Acquire the mutex - blocks until it's available or the given time expires. Each call to acquire that returns true must be balanced by a call
* to {@link #release()}
*
* @param time time to wait
* @param unit time unit
* @return true if the mutex was acquired, false if not
* @throws Exception ZK errors, connection interruptions
*/
public boolean acquire(long time, TimeUnit unit) throws Exception;
两种构建方法分别使用不同情况,两者都会尝试创建节点,不带构建参数的acquire方法若无法创建会阻塞主进程直至可创建或异常,带时间构造参数的acquire方法则会在指定时间段内尝试,如果在这段时间内没有成功创建,则会返回false,反之为true。各位可以根据自己的需求进行选择。
- 测试效果
-
服务1先进行调用,查看zk中新增了临时节点
-
服务2后进行调用