一、Redis锁
-
多个客户端,通过watch一个键-值,然后开启事务
-
如果在开启事务的期间,watch的值没有被其他客户端修改过,则执行成功
-
如果在开启事务的期间,watch的值被其他客户端修改了,则执行失败
set name erick
set age 10watch name age # 监控对应的属性
multi
set address shanxi
set year 2022
exec如果事务在执行期间,没有其他客户端去操作被watch的值,则A客户端的事物可以执行成功
如果想解除监控,unwatch
watch必须在开启事务之前
二、分布式锁
- 在集群模式下,synchronized只能保证单个JVM内部的线程互斥,不能保证跨JVM的互斥
1. 单个JVM
2. 多个JVM
3. 分布式锁
-
满足分布式系统或集群模式下多进程可见并互斥的锁
分布式锁特点
- 多进程可见: 必须多个jvm都能去访问到该锁资源
- 互斥: 锁资源必须是互斥
- 高可用: 锁的稳定性要得到保证
- 高性能: 加锁本来就会降低系统性能,如何保证
- 安全性: 锁假如无法释放怎么办
三、Redis分布式锁
1. 基础版本
-
单线程保证一定只有一个线程来获取锁
场景一: 假如锁匙放失败怎么半?
- 获取: SETNX k v
- 执行业务
- 释放锁 DEL k
场景二:
- 获取锁,并添加过期时间 SET K V EX 10 NX
- 执行业务
- 释放锁
package com.erick.redis;
import redis.clients.jedis.Jedis;
public class Demo01 {
public static final String LOCK_NAME = "LOCK";
public static final String LOCK_VALUE = "ERICK";
public static final int EXPIRE_SECS = 5;
private static Jedis getJedis() {
return new Jedis("60.205.229.31", 6381);
}
public static void main(String[] args) throws InterruptedException {
new Thread(() -> secondLock()).start();
new Thread(() -> secondLock()).start();
}
/*场景一: 假如释放锁失败,则后面永远无法执行*/
public static void firstLock() {
//1.上锁
Jedis redis = getJedis();
Long lockResult = redis.setnx(LOCK_NAME, LOCK_VALUE);
if (1 == lockResult) {
// 2. 执行业务
executeBusiness();
// 3. 释放锁
redis.del(LOCK_NAME);
} else {
// 获取锁失败
System.out.println("Can not get lock");
}