zoukankan      html  css  js  c++  java
  • redis分布式锁

    redis分布式锁原理:
    1、使用Redis的 SETNX 命令可以实现分布式锁
    SETNX命令:
    将 key 的值设为 value,当且仅当 key 不存在。 返回1
    若给定的 key 已经存在,则 SETNX 不做任何动作。 返回0
    SETNX 是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();
    }
  • 相关阅读:
    sharepoint权限操作(记录以备忘)
    python-----利用filecmp删除重复文件
    python-----自动解压并删除zip文件
    python-----文件自动归类
    python-----模糊搜索文件
    python-----查看显卡gpu信息
    python-----判断文件是否存在
    git 查看、切换用户
    PyCharm创建文件时自动添加头文件
    python-----监控博客园积分动态,有变化发邮件通知
  • 原文地址:https://www.cnblogs.com/liukunjava/p/8205463.html
Copyright © 2011-2022 走看看