欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java分布式鎖的三種實(shí)現(xiàn)方案

 更新時(shí)間:2017年01月20日 09:24:40   作者:本杰明警官  
本文主要介紹了Java分布式鎖的三種實(shí)現(xiàn)方案。具有一定的參考價(jià)值,下面跟著小編一起來看下吧

方案一:數(shù)據(jù)庫樂觀鎖

樂觀鎖通常實(shí)現(xiàn)基于數(shù)據(jù)版本(version)的記錄機(jī)制實(shí)現(xiàn)的,比如有一張紅包表(t_bonus),有一個(gè)字段(left_count)記錄禮物的剩余個(gè)數(shù),用戶每領(lǐng)取一個(gè)獎(jiǎng)品,對應(yīng)的left_count減1,在并發(fā)的情況下如何要保證left_count不為負(fù)數(shù),樂觀鎖的實(shí)現(xiàn)方式為在紅包表上添加一個(gè)版本號字段(version),默認(rèn)為0。

異常實(shí)現(xiàn)流程

-- 可能會發(fā)生的異常情況
-- 線程1查詢,當(dāng)前l(fā)eft_count為1,則有記錄
select * from t_bonus where id = 10001 and left_count > 0

-- 線程2查詢,當(dāng)前l(fā)eft_count為1,也有記錄
select * from t_bonus where id = 10001 and left_count > 0

-- 線程1完成領(lǐng)取記錄,修改left_count為0,
update t_bonus set left_count = left_count - 1 where id = 10001

-- 線程2完成領(lǐng)取記錄,修改left_count為-1,產(chǎn)生臟數(shù)據(jù)
update t_bonus set left_count = left_count - 1 where id = 10001

通過樂觀鎖實(shí)現(xiàn)

-- 添加版本號控制字段
ALTER TABLE table ADD COLUMN version INT DEFAULT '0' NOT NULL AFTER t_bonus;

-- 線程1查詢,當(dāng)前l(fā)eft_count為1,則有記錄,當(dāng)前版本號為1234
select left_count, version from t_bonus where id = 10001 and left_count > 0

-- 線程2查詢,當(dāng)前l(fā)eft_count為1,有記錄,當(dāng)前版本號為1234
select left_count, version from t_bonus where id = 10001 and left_count > 0

-- 線程1,更新完成后當(dāng)前的version為1235,update狀態(tài)為1,更新成功
update t_bonus set version = 1235, left_count = left_count-1 where id = 10001 and version = 1234

-- 線程2,更新由于當(dāng)前的version為1235,udpate狀態(tài)為0,更新失敗,再針對相關(guān)業(yè)務(wù)做異常處理
update t_bonus set version = 1235, left_count = left_count-1 where id = 10001 and version = 1234

方案二:基于Redis的分布式鎖

SETNX命令(SET if Not eXists)\
語法:SETNX key value\
功能:原子性操作,當(dāng)且僅當(dāng) key 不存在,將 key 的值設(shè)為 value ,并返回1;若給定的 key 已經(jīng)存在,則 SETNX 不做任何動作,并返回0。\
Expire命令\
語法:expire(key, expireTime)\
功能:key設(shè)置過期時(shí)間\
GETSET命令\
語法:GETSET key value\
功能:將給定 key 的值設(shè)為 value ,并返回 key 的舊值 (old value),當(dāng) key 存在但不是字符串類型時(shí),返回一個(gè)錯(cuò)誤,當(dāng)key不存在時(shí),返回nil。\
GET命令\
語法:GET key\
功能:返回 key 所關(guān)聯(lián)的字符串值,如果 key 不存在那么返回特殊值 nil 。\
DEL命令\
語法:DEL key [KEY …]\
功能:刪除給定的一個(gè)或多個(gè) key ,不存在的 key 會被忽略。

第一種:使用redis的setnx()、expire()方法,用于分布式鎖

  • setnx(lockkey, 1) 如果返回0,則說明占位失敗;如果返回1,則說明占位成功
  • expire()命令對lockkey設(shè)置超時(shí)時(shí)間,為的是避免死鎖問題。
  • 執(zhí)行完業(yè)務(wù)代碼后,可以通過delete命令刪除key。

這個(gè)方案其實(shí)是可以解決日常工作中的需求的,但從技術(shù)方案的探討上來說,可能還有一些可以完善的地方。比如,如果在第一步setnx執(zhí)行成功后,在expire()命令執(zhí)行成功前,發(fā)生了宕機(jī)的現(xiàn)象,那么就依然會出現(xiàn)死鎖的問題

第二種:使用redis的setnx()、get()、getset()方法,用于分布式鎖,解決死鎖問題

  • setnx(lockkey, 當(dāng)前時(shí)間+過期超時(shí)時(shí)間) ,如果返回1,則獲取鎖成功;如果返回0則沒有獲取到鎖,轉(zhuǎn)向2。
  • get(lockkey)獲取值oldExpireTime ,并將這個(gè)value值與當(dāng)前的系統(tǒng)時(shí)間進(jìn)行比較,如果小于當(dāng)前系統(tǒng)時(shí)間,則認(rèn)為這個(gè)鎖已經(jīng)超時(shí),可以允許別的請求重新獲取,轉(zhuǎn)向3。
  • 計(jì)算newExpireTime=當(dāng)前時(shí)間+過期超時(shí)時(shí)間,然后getset(lockkey, newExpireTime) 會返回當(dāng)前l(fā)ockkey的值currentExpireTime。
  • 判斷currentExpireTime與oldExpireTime 是否相等,如果相等,說明當(dāng)前getset設(shè)置成功,獲取到了鎖。如果不相等,說明這個(gè)鎖又被別的請求獲取走了,那么當(dāng)前請求可以直接返回失敗,或者繼續(xù)重試。
  • 在獲取到鎖之后,當(dāng)前線程可以開始自己的業(yè)務(wù)處理,當(dāng)處理完畢后,比較自己的處理時(shí)間和對于鎖設(shè)置的超時(shí)時(shí)間,如果小于鎖設(shè)置的超時(shí)時(shí)間,則直接執(zhí)行delete釋放鎖;如果大于鎖設(shè)置的超時(shí)時(shí)間,則不需要再鎖進(jìn)行處理。
import cn.com.tpig.cache.redis.RedisService;
import cn.com.tpig.utils.SpringUtils;
/**
 * Created by IDEA
 * User: shma1664
 * Date: 2016-08-16 14:01
 * Desc: redis分布式鎖
 */
public final class RedisLockUtil {
 private static final int defaultExpire = 60;
 private RedisLockUtil() {
 //
 }
 /**
 * 加鎖
 * @param key redis key
 * @param expire 過期時(shí)間,單位秒
 * @return true:加鎖成功,false,加鎖失敗
 */
 public static boolean lock(String key, int expire) {
 RedisService redisService = SpringUtils.getBean(RedisService.class);
 long status = redisService.setnx(key, "1");

 if(status == 1) {
 redisService.expire(key, expire);
 return true;
 }
 return false;
 }
 public static boolean lock(String key) {
 return lock2(key, defaultExpire);
 }
 /**
 * 加鎖
 * @param key redis key
 * @param expire 過期時(shí)間,單位秒
 * @return true:加鎖成功,false,加鎖失敗
 */
 public static boolean lock2(String key, int expire) {
 RedisService redisService = SpringUtils.getBean(RedisService.class);
 long value = System.currentTimeMillis() + expire;
 long status = redisService.setnx(key, String.valueOf(value));
 if(status == 1) {
 return true;
 }
 long oldExpireTime = Long.parseLong(redisService.get(key, "0"));
 if(oldExpireTime < System.currentTimeMillis()) {
 //超時(shí)
 long newExpireTime = System.currentTimeMillis() + expire;
 long currentExpireTime = Long.parseLong(redisService.getSet(key, String.valueOf(newExpireTime)));
 if(currentExpireTime == oldExpireTime) {
 return true;
 }
 }
 return false;
 }
 public static void unLock1(String key) {
 RedisService redisService = SpringUtils.getBean(RedisService.class);
 redisService.del(key);
 }
 public static void unLock2(String key) { 
 RedisService redisService = SpringUtils.getBean(RedisService.class); 
 long oldExpireTime = Long.parseLong(redisService.get(key, "0")); 
 if(oldExpireTime > System.currentTimeMillis()) { 
 redisService.del(key); 
 }
 }
}

public void drawRedPacket(long userId) {
 String key = "draw.redpacket.userid:" + userId;
 boolean lock = RedisLockUtil.lock2(key, 60);
 if(lock) {
 try {
 //領(lǐng)取操作
 } finally {
 //釋放鎖
 RedisLockUtil.unLock(key);
 }
 } else {
 new RuntimeException("重復(fù)領(lǐng)取獎(jiǎng)勵(lì)");
 }
}

Spring AOP基于注解方式和SpEL實(shí)現(xiàn)開箱即用的redis分布式鎖策略

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * RUNTIME
 * 定義注解
 * 編譯器將把注釋記錄在類文件中,在運(yùn)行時(shí) VM 將保留注釋,因此可以反射性地讀取。
 * @author shma1664
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RedisLockable {
 String[] key() default "";
 long expiration() default 60;
}
import javax.annotation.Resource;
import java.lang.reflect.Method;
import com.autohome.api.dealer.util.cache.RedisClient;
import com.google.common.base.Joiner;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
/**
 * Created by IDEA
 * User: mashaohua
 * Date: 2016-09-28 18:08
 * Desc:
 */
@Aspect
@Component
public class RedisLockAop {
 @Resource
 private RedisClient redisClient;
 @Pointcut("execution(* com.autohome.api.dealer.tuan.service.*.*(..))")
 public void pointcut(){}
 @Around("pointcut()")
 public Object doAround(ProceedingJoinPoint point) throws Throwable{
 Signature signature = point.getSignature();
 MethodSignature methodSignature = (MethodSignature) signature;
 Method method = methodSignature.getMethod();
 String targetName = point.getTarget().getClass().getName();
 String methodName = point.getSignature().getName();
 Object[] arguments = point.getArgs();
 if (method != null && method.isAnnotationPresent(RedisLockable.class)) {
 RedisLockable redisLock = method.getAnnotation(RedisLockable.class);
 long expire = redisLock.expiration();
 String redisKey = getLockKey(targetName, methodName, redisLock.key(), arguments);
 boolean isLock = RedisLockUtil.lock2(redisKey, expire);
 if(!isLock) {
 try {
 return point.proceed();
 } finally {
 unLock2(redisKey);
 }
 } else {
 throw new RuntimeException("您的操作太頻繁,請稍后再試");
 }
 }
 return point.proceed();
 }
 private String getLockKey(String targetName, String methodName, String[] keys, Object[] arguments) {
 StringBuilder sb = new StringBuilder();
 sb.append("lock.").append(targetName).append(".").append(methodName);
 if(keys != null) {
 String keyStr = Joiner.on(".").skipNulls().join(keys);
 String[] parameters = ReflectParamNames.getNames(targetName, methodName);
 ExpressionParser parser = new SpelExpressionParser();
 Expression expression = parser.parseExpression(keyStr);
 EvaluationContext context = new StandardEvaluationContext();
 int length = parameters.length;
 if (length > 0) {
 for (int i = 0; i < length; i++) {
 context.setVariable(parameters[i], arguments[i]);
 }
 }
 String keysValue = expression.getValue(context, String.class);
 sb.append("#").append(keysValue);
 }
 return sb.toString();
 }
<!-- https://mvnrepository.com/artifact/javassist/javassist -->
<dependency>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 <version>3.18.1-GA</version>
</dependency>
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.log4j.Logger;
/**
 * Created by IDEA
 * User: mashaohua
 * Date: 2016-09-28 18:39
 * Desc:
 */
public class ReflectParamNames {
 private static Logger log = Logger.getLogger(ReflectParamNames.class);
 private static ClassPool pool = ClassPool.getDefault();
 static{
 ClassClassPath classPath = new ClassClassPath(ReflectParamNames.class);
 pool.insertClassPath(classPath);
 }
 public static String[] getNames(String className,String methodName) {
 CtClass cc = null;
 try {
 cc = pool.get(className);
 CtMethod cm = cc.getDeclaredMethod(methodName);
 // 使用javaassist的反射方法獲取方法的參數(shù)名
 MethodInfo methodInfo = cm.getMethodInfo();
 CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
 LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
 if (attr == null) return new String[0];
 int begin = 0;
 String[] paramNames = new String[cm.getParameterTypes().length];
 int count = 0;
 int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
 for (int i = 0; i < attr.tableLength(); i++){
 // 為什么 加這個(gè)判斷,發(fā)現(xiàn)在windows 跟linux執(zhí)行時(shí),參數(shù)順序不一致,通過觀察,實(shí)際的參數(shù)是從this后面開始的
 if (attr.variableName(i).equals("this")){
 begin = i;
 break;
 }
 }
 for (int i = begin+1; i <= begin+paramNames.length; i++){
 paramNames[count] = attr.variableName(i);
 count++;
 }
 return paramNames;
 } catch (Exception e) {
 e.printStackTrace();
 }finally{
 try {
 if(cc != null) cc.detach();
 } catch (Exception e2) {
 log.error(e2.getMessage());
 }
 }
 return new String[0];
 }
}

在需要使用分布式鎖的地方添加注解

/**
 * 抽獎(jiǎng)接口
 * 添加redis分布式鎖保證一個(gè)訂單只有一個(gè)請求處理,防止用戶刷禮物,支持SpEL表達(dá)式
 * redisLockKey:lock.com.autohome.api.dealer.tuan.service.impl.drawBonus#orderId
 * @param orderId 訂單id
 * @return 抽中的獎(jiǎng)品信息
 */
@RedisLockable(key = {"#orderId"}, expiration = 120)
@Override
public BonusConvertBean drawBonus(Integer orderId) throws BonusException{
 // 業(yè)務(wù)邏輯
}

第三種方案:基于Zookeeper的分布式鎖

利用節(jié)點(diǎn)名稱的唯一性來實(shí)現(xiàn)獨(dú)占鎖

ZooKeeper機(jī)制規(guī)定同一個(gè)目錄下只能有一個(gè)唯一的文件名,zookeeper上的一個(gè)znode看作是一把鎖,通過createznode的方式來實(shí)現(xiàn)。所有客戶端都去創(chuàng)建/lock/${lock_name}_lock節(jié)點(diǎn),最終成功創(chuàng)建的那個(gè)客戶端也即擁有了這把鎖,創(chuàng)建失敗的可以選擇監(jiān)聽繼續(xù)等待,還是放棄拋出異常實(shí)現(xiàn)獨(dú)占鎖。
package com.shma.example.zookeeper.lock;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
/**
 * Created by IDEA
 * User: mashaohua
 * Date: 2016-09-30 16:09
 * Desc:
 */
public class ZookeeperLock implements Lock, Watcher {
 private ZooKeeper zk;
 private String root = "/locks";//根
 private String lockName;//競爭資源的標(biāo)志
 private String myZnode;//當(dāng)前鎖
 private int sessionTimeout = 30000;
 private List<Exception> exception = new ArrayList<Exception>();
 /**
 * 創(chuàng)建分布式鎖,使用前請確認(rèn)config配置的zookeeper服務(wù)可用
 * @param config 127.0.0.1:2181
 * @param lockName 競爭資源標(biāo)志,lockName中不能包含單詞lock
 */
 public ZookeeperLock(String config, String lockName){
 this.lockName = lockName;
 // 創(chuàng)建一個(gè)與服務(wù)器的連接
 try {
 zk = new ZooKeeper(config, sessionTimeout, this);
 Stat stat = zk.exists(root, false);
 if(stat == null){
 // 創(chuàng)建根節(jié)點(diǎn)
 zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
 }
 } catch (IOException e) {
 exception.add(e);
 } catch (KeeperException e) {
 exception.add(e);
 } catch (InterruptedException e) {
 exception.add(e);
 }
 }
 @Override
 public void lock() {
 if(exception.size() > 0){
 throw new LockException(exception.get(0));
 }
 if(!tryLock()) {
 throw new LockException("您的操作太頻繁,請稍后再試");
 }
 }
 @Override
 public void lockInterruptibly() throws InterruptedException {
 this.lock();
 }
 @Override
 public boolean tryLock() {
 try {
 myZnode = zk.create(root + "/" + lockName, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
 return true;
 } catch (KeeperException e) {
 e.printStackTrace();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 return false;
 }
 @Override
 public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
 return tryLock();
 }
 @Override
 public void unlock() {
 try {
 zk.delete(myZnode, -1);
 myZnode = null;
 zk.close();
 } catch (InterruptedException e) {
 e.printStackTrace();
 } catch (KeeperException e) {
 e.printStackTrace();
 }
 }
 @Override
 public Condition newCondition() {
 return null;
 }
 @Override
 public void process(WatchedEvent watchedEvent) {
 //
 }
}
ZookeeperLock lock = null;
try {
 lock = new ZookeeperLock("127.0.0.1:2182","test1");
 lock.lock();
 //業(yè)務(wù)邏輯處理
} catch (LockException e) {
 throw e;
} finally {
 if(lock != null)
 lock.unlock();
}

利用臨時(shí)順序節(jié)點(diǎn)控制時(shí)序?qū)崿F(xiàn)

/lock已經(jīng)預(yù)先存在,所有客戶端在它下面創(chuàng)建臨時(shí)順序編號目錄節(jié)點(diǎn),和選master一樣,編號最小的獲得鎖,用完刪除,依次方便。\

算法思路:對于加鎖操作,可以讓所有客戶端都去/lock目錄下創(chuàng)建臨時(shí)順序節(jié)點(diǎn),如果創(chuàng)建的客戶端發(fā)現(xiàn)自身創(chuàng)建節(jié)點(diǎn)序列號是/lock/目錄下最小的節(jié)點(diǎn),則獲得鎖。否則,監(jiān)視比自己創(chuàng)建節(jié)點(diǎn)的序列號小的節(jié)點(diǎn)(比自己創(chuàng)建的節(jié)點(diǎn)小的最大節(jié)點(diǎn)),進(jìn)入等待。

對于解鎖操作,只需要將自身創(chuàng)建的節(jié)點(diǎn)刪除即可。

package com.shma.example.zookeeper.lock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
/**
 * Created by IDEA
 * User: mashaohua
 * Date: 2016-09-30 16:09
 * Desc:
 */
public class DistributedLock implements Lock, Watcher{
 private ZooKeeper zk;
 private String root = "/locks";//根
 private String lockName;//競爭資源的標(biāo)志
 private String waitNode;//等待前一個(gè)鎖
 private String myZnode;//當(dāng)前鎖
 private CountDownLatch latch;//計(jì)數(shù)器
 private int sessionTimeout = 30000;
 private List<Exception> exception = new ArrayList<Exception>();
 /**
 * 創(chuàng)建分布式鎖,使用前請確認(rèn)config配置的zookeeper服務(wù)可用
 * @param config 127.0.0.1:2181
 * @param lockName 競爭資源標(biāo)志,lockName中不能包含單詞lock
 */
 public DistributedLock(String config, String lockName){
 this.lockName = lockName;
 // 創(chuàng)建一個(gè)與服務(wù)器的連接
 try {
 zk = new ZooKeeper(config, sessionTimeout, this);
 Stat stat = zk.exists(root, false);
 if(stat == null){
 // 創(chuàng)建根節(jié)點(diǎn)
 zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
 }
 } catch (IOException e) {
 exception.add(e);
 } catch (KeeperException e) {
 exception.add(e);
 } catch (InterruptedException e) {
 exception.add(e);
 }
 }
 /**
 * zookeeper節(jié)點(diǎn)的監(jiān)視器
 */
 public void process(WatchedEvent event) {
 if(this.latch != null) {
 this.latch.countDown();
 }
 }
 public void lock() {
 if(exception.size() > 0){
 throw new LockException(exception.get(0));
 }
 try {
 if(this.tryLock()){
 System.out.println("Thread " + Thread.currentThread().getId() + " " +myZnode + " get lock true");
 return;
 }
 else{
 waitForLock(waitNode, sessionTimeout);//等待鎖
 }
 } catch (KeeperException e) {
 throw new LockException(e);
 } catch (InterruptedException e) {
 throw new LockException(e);
 }
 }
 public boolean tryLock() {
 try {
 String splitStr = "_lock_";
 if(lockName.contains(splitStr))
 throw new LockException("lockName can not contains \\u000B");
 //創(chuàng)建臨時(shí)子節(jié)點(diǎn)
 myZnode = zk.create(root + "/" + lockName + splitStr, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
 System.out.println(myZnode + " is created ");
 //取出所有子節(jié)點(diǎn)
 List<String> subNodes = zk.getChildren(root, false);
 //取出所有l(wèi)ockName的鎖
 List<String> lockObjNodes = new ArrayList<String>();
 for (String node : subNodes) {
 String _node = node.split(splitStr)[0];
 if(_node.equals(lockName)){
 lockObjNodes.add(node);
 }
 }
 Collections.sort(lockObjNodes);
 System.out.println(myZnode + "==" + lockObjNodes.get(0));
 if(myZnode.equals(root+"/"+lockObjNodes.get(0))){
 //如果是最小的節(jié)點(diǎn),則表示取得鎖
 return true;
 }
 //如果不是最小的節(jié)點(diǎn),找到比自己小1的節(jié)點(diǎn)
 String subMyZnode = myZnode.substring(myZnode.lastIndexOf("/") + 1);
 waitNode = lockObjNodes.get(Collections.binarySearch(lockObjNodes, subMyZnode) - 1);
 } catch (KeeperException e) {
 throw new LockException(e);
 } catch (InterruptedException e) {
 throw new LockException(e);
 }
 return false;
 }
 public boolean tryLock(long time, TimeUnit unit) {
 try {
 if(this.tryLock()){
 return true;
 }
 return waitForLock(waitNode,time);
 } catch (Exception e) {
 e.printStackTrace();
 }
 return false;
 }
 private boolean waitForLock(String lower, long waitTime) throws InterruptedException, KeeperException {
 Stat stat = zk.exists(root + "/" + lower,true);
 //判斷比自己小一個(gè)數(shù)的節(jié)點(diǎn)是否存在,如果不存在則無需等待鎖,同時(shí)注冊監(jiān)聽
 if(stat != null){
 System.out.println("Thread " + Thread.currentThread().getId() + " waiting for " + root + "/" + lower);
 this.latch = new CountDownLatch(1);
 this.latch.await(waitTime, TimeUnit.MILLISECONDS);
 this.latch = null;
 }
 return true;
 }
 public void unlock() {
 try {
 System.out.println("unlock " + myZnode);
 zk.delete(myZnode,-1);
 myZnode = null;
 zk.close();
 } catch (InterruptedException e) {
 e.printStackTrace();
 } catch (KeeperException e) {
 e.printStackTrace();
 }
 }
 public void lockInterruptibly() throws InterruptedException {
 this.lock();
 }
 public Condition newCondition() {
 return null;
 }
 public class LockException extends RuntimeException {
 private static final long serialVersionUID = 1L;
 public LockException(String e){
 super(e);
 }
 public LockException(Exception e){
 super(e);
 }
 }
}

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • Spring基于Aop實(shí)現(xiàn)事務(wù)管理流程詳細(xì)講解

    Spring基于Aop實(shí)現(xiàn)事務(wù)管理流程詳細(xì)講解

    這篇文章主要介紹了Spring基于Aop實(shí)現(xiàn)事務(wù)管理流程,事務(wù)管理對于企業(yè)應(yīng)用來說是至關(guān)重要的,即使出現(xiàn)異常情況,它也可以保證數(shù)據(jù)的一致性,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • java設(shè)計(jì)模式之裝飾器模式(Decorator)

    java設(shè)計(jì)模式之裝飾器模式(Decorator)

    這篇文章主要為大家詳細(xì)介紹了java設(shè)計(jì)模式之裝飾器模式Decorator,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Spring Cache相關(guān)知識總結(jié)

    Spring Cache相關(guān)知識總結(jié)

    今天帶大家學(xué)習(xí)Spring的相關(guān)知識,文中對Spring Cache作了非常詳細(xì)的介紹,對正在學(xué)習(xí)Java Spring的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • 常用Java排序算法詳解

    常用Java排序算法詳解

    本文主要介紹了java的七種常見排序算法的實(shí)現(xiàn),對選擇排序、插入排序、冒泡排序、歸并排序、快速排序、希爾排序、最小堆排序進(jìn)行原理分析與實(shí)例介紹,具有很好的參考價(jià)值。下面就跟著小編一起來看下吧
    2016-12-12
  • java對象克隆實(shí)現(xiàn)方法詳解

    java對象克隆實(shí)現(xiàn)方法詳解

    這篇文章主要給大家介紹了關(guān)于java對象克隆實(shí)現(xiàn)的相關(guān)資料,克隆就是復(fù)制一個(gè)對象的副本,Java支持我們對一個(gè)對象進(jìn)行克隆,通常用在裝飾模式和原型模式中,需要的朋友可以參考下
    2023-06-06
  • Windows10 Java環(huán)境變量配置過程圖解

    Windows10 Java環(huán)境變量配置過程圖解

    這篇文章主要介紹了Windows10 Java環(huán)境變量配置過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • IDEA如何對單個(gè)的java class文件打成jar包

    IDEA如何對單個(gè)的java class文件打成jar包

    這篇文章主要介紹了IDEA如何對單個(gè)的java class文件打成jar包問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作

    java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作

    這篇文章主要介紹了java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Mybatis-plus使用注解 @TableField(exist = false)

    Mybatis-plus使用注解 @TableField(exist = false)

    這篇文章主要介紹了Mybatis-plus使用注解 @TableField(exist = false),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • SpringBoot整合MQTT小結(jié)匯總

    SpringBoot整合MQTT小結(jié)匯總

    MQTT 客戶端是運(yùn)行 MQTT 庫并通過網(wǎng)絡(luò)連接到 MQTT 代理的任何設(shè)備,是一種基于發(fā)布/訂閱(publish/subscribe)模式的“輕量級”通訊協(xié)議,該協(xié)議構(gòu)建于 TCP/IP 協(xié)議上,由 IBM 于 1999 年發(fā)明,對SpringBoot整合MQTT相關(guān)知識感興趣的朋友一起看看吧
    2022-01-01

最新評論