curator分布式锁,大概过程:
创建临时有序节点,排序,最先创建节点的获取到锁,其他节点监听前一个节点删除事件。当监听到时,则重新进行排序,index最小的获取到锁。
public class lockService {
@Autowired
private ZookeeperDao dao;
InterProcessMutex lock = new InterProcessMutex(new CuratorClient().getClient(),"/lock");
public void loclMethod(){
try {
//获取锁
//一直等待锁
//lock.acquire();
//尝试获取锁,如果在指定时间获取锁,则返回true
if (lock.acquire(1000, TimeUnit.SECONDS)){
int check = dao.check();
if (check > 0){
System.out.println("售出");
dao.des(--check);
}else {
System.out.println("没有库存");
}
}
//Thread.sleep(50);
} catch (Exception e) {
System.out.println(e);
}finally {
try {
//释放锁
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
interProcessMutex.acquire(1000, TimeUnit.SECONDS)
public class InterProcessMutex implements InterProcessLock, Revocable
{
private final LockInternals internals;
private final String basePath;
private final ConcurrentMap threadData = Maps.newConcurrentMap();
private static class LockData
{
final Thread owningThread;
final String lockPath;
//分布式锁重入次数
final AtomicInteger lockCount = new AtomicInteger(1);
private LockData(Thread owningThread, String lockPath)
{
this.owningThread = owningThread;
this.lockPath = lockPath;
}
}
private static final String LOCK_NAME = "lock-";
@Override
public void acquire() throws Exception
{ //获取锁,一直等待
if ( !internalLock(-1, null) )
{
throw new IOException("Lost connection while trying to acquire lock: " + basePath);
}
}
//获取锁,等待指定时间
@Override
public boolean acquire(long time, TimeUnit unit) throws Exception
{
return internalLock(time, unit);
}
private boolean internalLock(long time, TimeUnit unit) throws Exception
{ //获取当前线程
Thread currentThread = Thread.currentThread();
//从ConcurrentMap中获取当前线程的锁数据,不为空,则直接获取锁
LockData lockData = threadData.get(currentThread);
if ( lockData != null )
{ //实现可重入
// 统计重入次数
lockData.lockCount.incrementAndGet();
return true;
}
//ConcurrentMap中没有当前线程的所数据,则当前线程尝试去获取锁
String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
if ( lockPath != null )
{ //获取到锁,封装锁数据
LockData newLockData = new LockData(currentThread, lockPath);
//保存到ConcurrentMap缓存中
threadData.put(currentThread, newLockData);
return true;
}
return false;
}
}
尝试获取锁
String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
public class LockInternals
{
String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception
{
final long startMillis = System.currentTimeMillis();
//无线等待时millisToWait 为null
final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;
//节点数据
final byte[] localLockNodeBytes = (revocable.get() != null) ? new byte[0] : lockNodeBytes;
//当前重试获取锁次数
int retryCount = 0;
// 在Zookeeper中创建的临时顺序节点的路径,相当于一把待激活的分布式锁
// 激活条件:同级目录子节点,名称排序最小(排队,公平锁)
String ourPath = null;
// 是否已经持有分布式锁
boolean hasTheLock = false;
// 是否已经完成尝试获取分布式锁的操作
boolean isDone = false;
while ( !isDone )
{
isDone = true;
try
{ //StandardLockInternalsDriver,创建有序临时节点
ourPath = driver.createsTheLock(client, path, localLockNodeBytes);
//是否获取当前锁
hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);
}
catch ( KeeperException.NoNodeException e )
{
if ( client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper()) )
{
isDone = false;
}
else
{
throw e;
}
}
}
if ( hasTheLock )
{ //成功获取锁
return ourPath;
}
return null;
}
//是否获取当锁
private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception
{ //是否拥有分布式锁
boolean haveTheLock = false;
//是否需要删除子节点
boolean doDelete = false;
try
{
if ( revocable.get() != null )
{
client.getData().usingWatcher(revocableWatcher).forPath(ourPath);
}
//循环尝试获取锁
while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock )
{ //排序节点
List children = getSortedChildren();
// 获取前面自己创建的临时顺序子节点的名称
String sequenceNodeName = ourPath.substring(basePath.length() + 1);
// StandardLockInternalsDriver
//判断是否回去锁,没有获取返回监听路径
PredicateResults predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
if ( predicateResults.getsTheLock() )
{ //获得锁
haveTheLock = true;
}
else
{ //没有所得到锁,监听上一个临时顺序节点
String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();
synchronized(this)
{
try
{ //上一个临时顺序节点如果被删除,会唤醒当前线程继续竞争锁
client.getData().usingWatcher(watcher).forPath(previousSequencePath);
if ( millisToWait != null )
{
millisToWait -= (System.currentTimeMillis() - startMillis);
startMillis = System.currentTimeMillis();
if ( millisToWait <= 0 )
{ //获取锁超时,标记删除之前创建的临时顺序节点
doDelete = true;
break;
}
wait(millisToWait);
}
else
{
wait();
}
}
catch ( KeeperException.NoNodeException e )
{
// it has been deleted (i.e. lock released). Try to acquire again
}
}
}
}
}
catch ( Exception e )
{
ThreadUtils.checkInterrupted(e);
doDelete = true;
throw e;
}
finally
{
if ( doDelete )
{
deleteOurPath(ourPath);
}
}
return haveTheLock;
}
//创建有序临时节点
@Override
public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception
{
String ourPath;
if ( lockNodeBytes != null )
{
ourPath = client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, lockNodeBytes);
}
else
{
ourPath = client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
}
return ourPath;
}
}
StandardLockInternalsDriver.getsTheLock(client, children, sequenceNodeName, maxLeases);
public class StandardLockInternalsDriver implements LockInternalsDriver
{
@Override
public PredicateResults getsTheLock(CuratorFramework client, List children, String sequenceNodeName, int maxLeases) throws Exception
{ // 之前创建的临时顺序节点在排序后的子节点列表中的索引
int ourIndex = children.indexOf(sequenceNodeName);
// 校验之前创建的临时顺序节点是否有效
validateOurIndex(sequenceNodeName, ourIndex);
//maxLeases 初始化为1
//ourIndex 为0 表示是当前排序的节点里最先创建出节点的连接,也就是越早创建节点的越早获取到锁
boolean getsTheLock = ourIndex < maxLeases;
//获取到锁则不需要监听,没有获取到锁,则监听前一个节点的删除事件
String pathToWatch = getsTheLock ? null : children.get(ourIndex - maxLeases);
// 返回获取锁的结果,交由上层继续处理(添加监听等操作)
return new PredicateResults(pathToWatch, getsTheLock);
}
//校验节点有效性
static void validateOurIndex(String sequenceNodeName, int ourIndex) throws KeeperException
{
if ( ourIndex < 0 )
{ // 由于会话过期或连接丢失等原因,该线程创建的临时顺序节点被Zookeeper服务端删除,往外抛出NoNodeException
throw new KeeperException.NoNodeException("Sequential path not found: " + sequenceNodeName);
}
}
}
释放锁
public class InterProcessMutex implements InterProcessLock, Revocable
{
@Override
public void release() throws Exception
{
Thread currentThread = Thread.currentThread();
LockData lockData = threadData.get(currentThread);
if ( lockData == null )
{ // 无法从映射表中获取锁信息,不持有锁
throw new IllegalMonitorStateException("You do not own the lock: " + basePath);
}
int newLockCount = lockData.lockCount.decrementAndGet();
if ( newLockCount > 0 )
{ // 锁是可重入的,初始值为1,原子-1到0,锁才释放
return;
}
if ( newLockCount < 0 )
{
throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + basePath);
}
try
{ //释放锁
internals.releaseLock(lockData.lockPath);
}
finally
{ //从映射中删除当前线程信息
threadData.remove(currentThread);
}
}
}
public class LockInternals
{
final void releaseLock(String lockPath) throws Exception
{ //删除监听
client.removeWatchers();
revocable.set(null);
//删除节点
deleteOurPath(lockPath);
}
private void deleteOurPath(String ourPath) throws Exception
{
try
{ // 后台不断尝试删除
client.delete().guaranteed().forPath(ourPath);
}
catch ( KeeperException.NoNodeException e )
{
// ignore - already deleted (possibly expired session, etc.)
}
}
}