redis和zookeeper做分布式锁参考

redis实现:

缺点:  1, 获取锁的结点服务器的线程如果意外中止(没有释放锁),则锁要等超时才能释放, 2, 应用要在过期时间内处理完业务,锁的时间过期后,会自动释放.

 

import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * redis相关的工具
 * @author Justin
 */
public class RedisTool {
 private static String LOCK_PREFIX = "basisLock:";
 /**
  * 锁的默认时长
  */
 public static Long LOCK_DEF_MILLI = 60 * 1000L;
 /**
  * 全局收货地址变更时,收集通知时,为了控制进度添加的锁
  */
 public static String LOCK_GSA = "gsa:";
 /**
  * redis的简易分布式锁
  * 参考: https://www.cnblogs.com/kiko2014551511/p/11801138.html
  *   https://www.jianshu.com/p/6dd656e7051f
  * @param rt
  * @param key
  * @param lockExpireMils
  * @return
  */
 public static boolean tryLock(RedisTemplate rt, String key, long lockExpireMils){
  String lock = LOCK_PREFIX + key;
  RedisSerializer keySerl = rt.getKeySerializer();
  return (Boolean) rt.execute((RedisCallback) connection -> {
   long nowTime = System.currentTimeMillis();
   long expireAt = nowTime + lockExpireMils + 1;
   Boolean acquire = connection.setNX(keySerl.serialize(lock), String.valueOf(expireAt).getBytes());
   if (acquire) {
    // 设置key的过期时间
    rt.expire(lock, lockExpireMils-2, TimeUnit.MILLISECONDS);
    return true;
   } else {
    byte[] value = connection.get(keySerl.serialize(lock));
    if (Objects.nonNull(value) && value.length > 0) {
     long expireTime = Long.parseLong(new String(value));
     if (expireTime < nowTime) {// 过期了
      byte[] oldValue = connection.getSet(keySerl.serialize(lock), String.valueOf(expireAt).getBytes());
      if(oldValue==null){
       // 锁被释放了
       acquire = connection.setNX(keySerl.serialize(lock), String.valueOf(expireAt).getBytes());
       if(acquire) {
        rt.expire(lock, lockExpireMils - 2, TimeUnit.MILLISECONDS);
        return true;
       }
       return false;
      }
      // 并发获取锁,如果得到的是过期的锁,则代表新锁设置成功
      boolean lockOK = Long.parseLong(new String(oldValue)) < nowTime;
      if(lockOK){
       // 获取到过期的锁,才能续时
       rt.expire(lock, lockExpireMils+1, TimeUnit.MILLISECONDS);
      }
      return lockOK;
     }
    }
   }
   return false;
  });
 }

 /**
  * redis的简易分布式锁-刷新锁
  * 参考: https://www.cnblogs.com/kiko2014551511/p/11801138.html
  *   https://www.jianshu.com/p/6dd656e7051f
  * @param rt
  * @param key
  * @param lockExpireMils
  * @return
  */
 public static void renewLock(RedisTemplate rt, String key, long lockExpireMils){
  String lock = LOCK_PREFIX + key;

  long expireAt = System.currentTimeMillis() + lockExpireMils + 1;
  rt.opsForValue().set(lock, expireAt);
  rt.expire(lock, lockExpireMils+1, TimeUnit.MILLISECONDS);
 }

 /**
  * redis的简易分布式锁-释放锁
  * 参考: https://www.cnblogs.com/kiko2014551511/p/11801138.html
  *   https://www.jianshu.com/p/6dd656e7051f
  * @param rt
  * @param key
  * @return
  */
 public static void unlock(RedisTemplate rt, String key){
  String lock = LOCK_PREFIX + key;
  rt.delete(key);
 }
}

 

 

zookeeper实现:

缺点: 1,  没有锁超时时间,如果线程卡住了,锁一直不会释放(待确认),  2, 由于zookeeper的实现机制(在硬盘上写数据)的原因,性能不如redis

public static CuratorFramework clientCF;  // zookeeper集群的代理对象。它是线程安全的
    	/**
	 * zookeeper Curator
	 * http://macrochen.iteye.com/blog/1366136/
	 * http://blog.youkuaiyun.com/yin380697242/article/details/52293771
		https://segmentfault.com/a/1190000018813672
	 * @param args
	 */
	public static void initCurator(){
		if(clientCF!=null){
			return ;
		}
		
		try{
			 String zkUrl="192.168.1.177:2381,192.168.1.177:2382,192.168.1.177:2383";
			 // RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
			 //clientCF = CuratorFrameworkFactory.builder().connectString(zkUrl).namespace("/test3")  
			 //        .retryPolicy(retryPolicy).connectionTimeoutMs(5000).build();  


			 clientCF = CuratorFrameworkFactory.builder().connectString(zkUrl).retryPolicy(new RetryNTimes(3, 1000))  
			         .connectionTimeoutMs(5000).build();  
			 clientCF.start();
		}catch(Exception e){	
			log.info(e.getMessage(), e);
		}
	}



	private static final String ZK_LOCK_PATH = "/zktest3";
	private static void doWithLock(CuratorFramework client) {
        InterProcessMutex lock = new InterProcessMutex(client, ZK_LOCK_PATH);
        try {
            if (lock.acquire(10 * 1000, TimeUnit.SECONDS)) {
                Comn.pl(Thread.currentThread().getName() + " hold lock");
                Thread.sleep(5000L);
                Comn.pl(Thread.currentThread().getName() + " release lock");
            }
        } catch (Exception e) {
        	log.info(e.getMessage(), e);
        } finally {
            try {
                lock.release();
            } catch (Exception e) {
            	log.info(Thread.currentThread().getName()+" "+e.getMessage(), e);
            }
        }

    }


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值