redis分布式锁

╄→гoц情女王★ 提交于 2020-01-17 03:55:27
redis分布式锁原理:1、使用Redis的 SETNX 命令可以实现分布式锁SETNX命令:
将 key 的值设为 value,当且仅当 key 不存在。 返回1若给定的 key 已经存在,则 SETNX 不做任何动作。 返回0SETNX 是SET if Not eXists的简写。public class RedisLock implements Lock{   /**锁定资源的key**/     private final String lockName;     /**持有锁的最长时间**/     private final int expireTime = 300;     /**获取不到锁的休眠时间**/     private final long sleepTime = 100;     /**锁中断状态**/     private boolean interruped = true;     /**超时时间**/     private long expireTimeOut = 0;     RedisClientTemplate redisClient = SpringContextHolder   .getBean("redisClientTemplate");      public RedisLock(String lockName){       this.lockName = lockName;     }       @Override   public void lock() {      // TODO Auto-generated method stub      if (lockName == null)             throw new NullPointerException("key is null");         while (true){                if (!interruped)                    throw new RuntimeException("获取锁状态被中断");                long id = redisClient.setnx(lockName, lockName);                if (id == 0L){                    try {                        Thread.currentThread().sleep(this.sleepTime);                    }catch (InterruptedException e){                        e.printStackTrace();                    }                }else{                    expireTimeOut = System.currentTimeMillis()/1000 + expireTime;                    redisClient.expireAt(this.lockName, expireTimeOut);                    break;                }            }    }   @Override   public void lockInterruptibly() throws InterruptedException {      // TODO Auto-generated method stub      this.interruped = false;     }   @Override   public Condition newCondition() {      // TODO Auto-generated method stub      return null;   }   @Override   public boolean tryLock() {      // TODO Auto-generated method stub        if (redisClient == null)                throw new NullPointerException("jedis is null");            if (lockName == null)                throw new NullPointerException("lockName is null");            if (!interruped)                throw  new RuntimeException("线程被中断");            long id = redisClient.setnx(lockName, lockName);            if (id == 0L)                return false;            else {                // 设置锁过期时间                expireTimeOut = System.currentTimeMillis()/1000 + expireTime;                redisClient.expireAt(this.lockName, expireTimeOut);                return true;            }    }   @Override   public boolean tryLock(long time, TimeUnit unit)         throws InterruptedException {      if (redisClient == null)             throw new NullPointerException("jedis is null");         if (lockName == null)             throw new NullPointerException("lockName is null");         if (time == 0)             return false;         long now = System.currentTimeMillis();         long timeOutAt = now + DateUtil.calcSeconds(time, unit);       while (true){             if (!interruped)                 throw new InterruptedException("线程被中断");             long id = redisClient.setnx(this.lockName, this.lockName);             // id = 0 表示加锁失败             if(id == 0){                 // 获取锁超时                 if(System.currentTimeMillis() > timeOutAt){                   return false;                 }               try {                     // 休眠一段时间,继续获取锁                     Thread.currentThread().sleep(this.sleepTime);                 }catch (InterruptedException e){                     e.printStackTrace();                 }           }else {                 //获取锁成功,设置锁过期时间                 expireTimeOut = System.currentTimeMillis()/1000 + expireTime;                 redisClient.expireAt(this.lockName, expireTimeOut);                 return true;             }         }     }补充:为了让分布式锁的算法更稳键些,持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时,再去做DEL操作,因为可能客户端因为某个耗时的操作而挂起,操作完的时候锁因为超时已经被别人获得,这时就不必解锁了。 注释掉的部分是为了确保拿到锁的线程释放锁   @Override   public void unlock() {      // TODO Auto-generated method stub      // try {                        if (System.currentTimeMillis() / 1000 < expireTimeOut)  {                 redisClient.del(lockName);         //   }catch (Exception e){                   // }finally {             //  redisClient.del(lockName);            //}     }   }以下是处理并发应用的代码块:
RedisLock lock = new RedisLock("key");try {    if(lock.tryLock(3, TimeUnit.SECONDS)){        //共享资源的操作    lock.unlock();
    }}catch (Exception e){
  e.printStackTrace();
}finally {  //  lock.unlock();}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!