关于redis:redis-分布式锁

36次阅读

共计 1820 个字符,预计需要花费 5 分钟才能阅读完成。

在 java 中,咱们能够用 synchronized 进行加锁,也能够用 lock 的 lock 办法加锁和 unlock 办法开释锁。然而在多个过程或者夸服务器的状况下,这种加锁的形式就没方法用了,因为他没方法让其余客户端的人晓得是否被加锁了。所以咱们能够用 redis、zookeeper、etcd 等来实现。redis 也有相似于 lock 的乐观锁,在 redis – 商品交易中也展现了 WATCH 的应用,然而当 key 里的内容足够多时,监控频繁的变动反而导致性能的降落。
java 的 map,有 putIfAbsent 办法,意思是如果对应的 key 曾经赋值了,则不能持续赋值。redis 中,也有相似的办法,setnx,SET if Not eXists,也是如果对应的 key 有值了,则不能持续赋值,所以咱们能够用他这个办法作为分布式锁。

// 锁的 key
static String lockName = "lock:";
static int cnt = 1000;
static CountDownLatch countDownLatch = new CountDownLatch(cnt);

@Test
public void testLock() throws InterruptedException {JedisUtils.del(lockName);
    // 锁的工夫,达到这个工夫就开释
    int lockTime = 1;
    // 锁的超时工夫,达到这个工夫就放弃获取
    long timeOut = 2500;
    for (int i = 0; i < cnt; i++) {new Thread(new LockThread(i, lockTime, timeOut)).start();
        countDownLatch.countDown();}
    TimeUnit.SECONDS.sleep(3);
}

static class LockThread implements Runnable {
    int lockTime;
    long timeOut;
    int idx;

    public LockThread(int idx, int lockTime, long timeOut) {
        this.idx = idx;
        this.lockTime = lockTime;
        this.timeOut = timeOut;
    }

    @Override
    public void run() {
        try {countDownLatch.await();
        } catch (InterruptedException e) {e.printStackTrace();
        }
        String lock = lock(lockName, lockTime, timeOut);
        if (StringUtils.isNotEmpty(lock)) {System.out.println(idx + ":获取到了锁");
            //JedisUtils.del(lockName);
        }
    }
}

private static String lock(String lockName, int lockTime, long timeOut) {long end = System.currentTimeMillis() + timeOut;
    String value = UUID.randomUUID().toString();
    while (System.currentTimeMillis() < end) {long setnx = JedisUtils.setnx(lockName, value);
        // 1 阐明获取锁,返回
        if (setnx == 1) {JedisUtils.expire(lockName, lockTime);
            return value;
        }
        try {
            // 没获取则休眠 100 毫秒持续抢锁
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {e.printStackTrace();
        }
    }
    return null;
}

失常状况下,下面的分布式锁能够运行的,然而有以下几个问题:

  1. 设置了生效工夫,如果在生效工夫内没执行完,则其余过程就会获取到锁,导致同一时间有多个过程获取同一个锁。
  2. 如果在生效工夫内获取到锁的过程曾经解体,锁仍然得不到开释,导致其余过程仍然在期待生效过期。
  3. 如果只有一个 redis 服务器,那服务器解体则不能失常运行。如果 redis 做主从,A 过程获取锁,且在主服务器数据未同步到从服务器的时候解体,B 过程读取曾经变成主服务器的原从服务器时,因为没有锁又获取到了锁,导致同一时间有多个过程获取同一个锁。

正文完
 0