基于Consul的分布式鎖主要利用Key/Value存儲API中的acquire和release操作來實現(xiàn)。acquire和release操作是類似Check-And-Set的操作:
acquire操作只有當鎖不存在持有者時才會返回true,并且set設置的Value值,同時執(zhí)行操作的session會持有對該Key的鎖,否則就返回false
release操作則是使用指定的session來釋放某個Key的鎖,如果指定的session無效,那么會返回false,否則就會set設置Value值,并返回true
未被上鎖

image.png
被上鎖

image.png
編碼如下
package com.qxwz.ops.station.change.util;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.kv.model.PutParams;
import com.ecwid.consul.v1.session.model.NewSession;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 基于Consul的互斥鎖
*
* @author muxin.sun
*/
public class Lock {
private static final String prefix = "lock/"; // 同步鎖參數前綴
private volatile String sessionId;
private final ConsulClient consulClient;
private final String sessionName;
private final String lockKey;
/**
*
* @param consulClient consul client
* @param sessionName 同步鎖的session名稱
* @param lockKey 同步鎖在consul的KV存儲中的Key路徑,會自動增加prefix前綴,方便歸類查詢
*/
public Lock(final ConsulClient consulClient,
final String sessionName,
final String lockKey) {
this.consulClient = consulClient;
this.sessionName = sessionName;
this.lockKey = prefix + lockKey;
}
/**
* 獲取同步鎖
*
* @param block 是否阻塞,直到獲取到鎖為止
* @return true OR false 獲取鎖成功
*/
public Boolean lock(boolean block) throws RuntimeException {
if (Objects.isNull(sessionId)) {
synchronized (Lock.class) {
if (Objects.isNull(sessionId)) {
sessionId = createSession(sessionName);
while(true) {
PutParams putParams = new PutParams();
putParams.setAcquireSession(sessionId);
if(consulClient.setKVValue(lockKey, "lock:" + LocalDateTime.now(), putParams).getValue()) {
return true;
} else if (block) {
continue;
}
return false;
}
}
}
}
throw new RuntimeException(sessionId + " - Already locked!");
}
/**
* 釋放同步鎖
*
* @return true OR false 釋放同步鎖成功
*/
public Boolean unlock() {
PutParams putParams = new PutParams();
putParams.setReleaseSession(sessionId);
boolean result = consulClient.setKVValue(lockKey, "unlock:" + LocalDateTime.now(), putParams).getValue();
consulClient.sessionDestroy(sessionId, null);
return result;
}
/**
* 創(chuàng)建session
* @param sessionName session name
* @return sessionId
*/
private String createSession(final String sessionName) {
NewSession newSession = new NewSession();
newSession.setName(sessionName);
return consulClient.sessionCreate(newSession, null).getValue();
}
}
參考如下:http://blog.didispace.com/spring-cloud-consul-lock-and-semphore/