江都建设网站,网建部,互联网优化营销,抖音小程序开发教程在很多场景中#xff0c;我们为了保证数据的最终一致性#xff0c;需要很多的技术方案来支持#xff0c;比如分布式事务、分布式锁等。那具体什么是分布式锁#xff0c;分布式锁应用在哪些业务场景、如何来实现分布式锁呢#xff1f;今天来探讨分布式锁这个话题。 什么是… 在很多场景中我们为了保证数据的最终一致性需要很多的技术方案来支持比如分布式事务、分布式锁等。那具体什么是分布式锁分布式锁应用在哪些业务场景、如何来实现分布式锁呢今天来探讨分布式锁这个话题。 什么是分布式锁 要介绍分布式锁首先要提到与分布式锁相对应的是线程锁、进程锁。 1.线程锁 主要用来给方法、代码块加锁。当某个方法或代码使用锁在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果因为线程锁的实现在根本上是依靠线程之间共享内存实现的比如Synchronized、Lock等。 2.进程锁 为了控制同一操作系统中多个进程访问某个共享资源因为进程具有独立性各个进程无法访问其他进程的资源因此无法通过synchronized等线程锁实现进程锁。 3.分布式锁 当多个进程不在同一个系统中用分布式锁控制多个进程对资源的访问。 分布式锁的由来 在传统单机部署的情况下可以使用Java并发处理相关的API如ReentrantLcok或synchronized进行互斥控制。 但是在分布式系统后由于分布式系统多线程、多进程并且分布在不同机器上这将使原单机并发控制锁策略失效为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问这就是分布式锁的由来。 当多个进程不在同一个系统中就需要用分布式锁控制多个进程对资源的访问。 分布式锁的特点 首先为了确保分布式锁可用我们至少要确保锁的实现同时满足以下四个条件 1、互斥性任意时刻只能有一个客户端获取锁不能同时有两个客户端获取到锁。 2、安全性锁只能被持有该锁的客户端删除不能由其它客户端删除。 3、死锁获取锁的客户端因为某些原因如down机等而未能释放锁其它客户端再也无法获取到该锁。 4、容错当部分节点redis节点等down机时客户端仍然能够获取锁和释放锁。 分布式锁的具体实现 分布式锁一般有三种实现方式 1. 数据库乐观锁 2. 基于ZooKeeper的分布式锁; 3.基于Redis的分布式锁 Redis实现分布式锁 基于Redis命令SET key value NX EX max-lock-time 这里补充下 从2.6.12版本后, 就可以使用set来获取锁, Lua 脚本来释放锁。setnx是老黄历了set命令nx,xx等参数, 是为了实现 setnx 的功能。 1.加锁 public class RedisTool { private static final String LOCK_SUCCESS “OK”; private static final String SET_IF_NOT_EXIST “NX”; private static final String SET_WITH_EXPIRE_TIME “PX”; /** * 尝试获取分布式锁 * param jedis Redis客户端 * param lockKey 锁 * param requestId 请求标识 * param expireTime 超期时间 * return 是否获取成功 */ public static boolean tryGetDistributedLockJedis jedis, String lockKey, String requestId, int expireTime { String result jedis.setlockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime;if LOCK_SUCCESS.equalsresult {return true;}return false;} } jedis.setString key, String value, String nxxx, String expx, int time 这个set方法一共有五个形参 第一个为key我们使用key来当锁因为key是唯一的。 第二个为value我们传的是requestId很多童鞋可能不明白有key作为锁不就够了吗为什么还要用到value原因就是我们在上面讲到可靠性时分布式锁要满足第四个条件解铃还须系铃人通过给value赋值为requestId我们就知道这把锁是哪个请求加的了在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID.toString方法生成。 第三个为nxxx这个参数我们填的是NX意思是SET IF NOT EXIST即当key不存在时我们进行set操作若key已经存在则不做任何操作 第四个为expx这个参数我们传的是PX意思是我们要给这个key加一个过期的设置具体时间由第五个参数决定。 第五个为time与第四个参数相呼应代表key的过期时间。 总的来说执行上面的set方法就只会导致两种结果1. 当前没有锁key不存在那么就进行加锁操作并对锁设置个有效期同时value表示加锁的客户端。2. 已有锁存在不做任何操作。 2.解锁 public class RedisTool { private static final Long RELEASE_SUCCESS 1L; /** * 释放分布式锁 * param jedis Redis客户端 * param lockKey 锁 * param requestId 请求标识 * return 是否释放成功 */ public static boolean releaseDistributedLockJedis jedis, String lockKey, String requestId { String script “if redis.call‘get’, KEYS[1] ARGV[1] then return redis.call‘del’, KEYS[1] else return 0 end”;Object result jedis.evalscript, Collections.singletonListlockKey,Collections.singletonListrequestId;if RELEASE_SUCCESS.equalsresult {return true;}return false;} } 那么这段Lua代码的功能是什么呢其实很简单首先获取锁对应的value值检查是否与requestId相等如果相等则删除锁解锁。 以上就是redis实现分布式锁详解除此之外也可以使用RedissionRedis 的客户端集成进来实现分布式锁也可以使用数据库等具体可以参考 阿里P8架构师谈分布式锁的3种实现数据库、缓存、Zookeeper 你可能也喜欢: Java多线程系列十一ReentrantReadWriteLock的实现原理与锁获取详解 Redis系列教程二详解Redis的存储类型、集群架构、以及应用场景 Redis系列教程三如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题 Redis系列教程五Redis哨兵、复制、集群的设计原理以及区别 Redis系列教程九Redis的内存回收原理及内存过期淘汰策略详解 Redis系列教程六Redis缓存和MySQL数据一致性方案详解