青岛网站建设招标网站功能板块
- 作者: 五速梦信息网
- 时间: 2026年03月21日 09:54
当前位置: 首页 > news >正文
青岛网站建设招标,网站功能板块,网站开发前期方案,怎样买网站建设简单解释一下个人理解的分布式锁以及主要的实现手段。 文章目录 什么是分布式锁常用分布式锁实现 什么是分布式锁
以java应用举例#xff0c;如果是单应用的情况下#xff0c;我们通常使用synchronized或者lock进行线程锁#xff0c;主要为了解决多线程或者高并发场景下的共… 简单解释一下个人理解的分布式锁以及主要的实现手段。 文章目录 什么是分布式锁常用分布式锁实现 什么是分布式锁
以java应用举例如果是单应用的情况下我们通常使用synchronized或者lock进行线程锁主要为了解决多线程或者高并发场景下的共享资源不能按照预期结果被处理。 举个最简单的例子总共有10件商品但是有100个人同时来消费我们需要保证永远只卖出10件商品否则多卖出的那件商品可就需要程序员来买单了。
那么什么又是分布式锁呢即上述的线程锁只能保证在同个jvm层面进行管控这个时候我们将该应用进行升级迭代为分布式架构即上述的购物服务可能被分布式部署为10套应用这个时候100个人来消费这件事情可能会被均匀地分摊到各个服务上。 那么我们就无法通过jvm锁来管控这若干个微服务的线程所以就需要引入分布式锁的概念通常需要引入第三方中间件的形式来完成分布式锁的功能。
常用分布式锁
Redis分布式锁 常见且推荐。MySQL分布式锁 特殊场景下可应用但是不推荐。Zookeeper分布式锁 使用zk的节点机制实现根据实际情况可以选用。
实现
通过上述了解我们明白redis分布式锁是较为常见的通常在工作过程中或者面试过程中也会经常使用到。所以下文我们主要着重就redis实现分布式锁进行阐述。 首先我们先了解为什么redis能够做分布式锁由于redis内部机制是单线程操作但是由于多路复用以及非阻塞io等特性我们完全可以不用担心其性能且作为一个kv缓存数据库我们可以极快的利用其kv存值特点进行管理从各个服务注册的redis的key。 例如服务1已经设置了一个约定好的key值这个时候服务2拿着同样的key值想进来这个时候就会通知服务2其他服务已经预定的这个key值了不好意思你得等着。在redis中就可以用setnx方法来实现该功能setnx即set if not exists的简写。 不知不觉我们就用redis实现了单机下用synchronized以及lock才能实现的锁机制。 只有setnx成功的服务才能够继续执行后续业务流程业务流程处理完成之后再进行释放锁即使用delete(key)进行清除缓存key。
这个时候我们又引申出另一个问题假设服务1的setnx成功了但是在执行业务过程中崩溃了。如果只是运行时异常还能够处理我们在finally中进行delete(key)的处理但是如果整个服务异常中断了这个时候就有一个很有意思的事情发生了其他若干个服务都在等着服务1释放锁但是由于服务1上了锁之后自己就崩溃了他也想释放但是丞妾做不到了。
其实要想解决这个问题也比较简单我们可以在上锁的时候设置有效时间嘛比如设置3s那么即使上述情况发生那么也只会影响3s。3s后该锁被自动释放其他的服务又可以开始愉快的争夺锁了。
说了这么多直接show me the code吧 前置条件引入starter-data-redis的pom依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId
/dependency首先我们使用RedisTemplate封装一个工具类
Component
public final class RedisUtil {Autowiredprivate RedisTemplateString, Object redisTemplate;// common/*** 指定缓存失效时间* param key 键* param time 时间(秒)/public boolean expire(String key, long time) {try {if (time 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/** 根据key 获取过期时间* param key 键 不能为null* return 时间(秒) 返回0代表为永久有效/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/** 判断key是否存在* param key 键* return true 存在 false不存在/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/** 删除缓存* param key 可以传一个值 或多个/SuppressWarnings(unchecked)public void del(String… key) {if (key ! null key.length 0) {if (key.length 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((CollectionString) CollectionUtils.arrayToList(key));}}}/** set nx上锁* param key 一般设为lock*param value 一般使用uuidparam time 缓存时间单位为s/public boolean setNx(String key, String value, int time){return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit.SECONDS));}//未指定过期时间/*** 未指定过期事件的redis锁* param key* param value* return/public boolean setNx(String key, String value){return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value));}// String/** 普通缓存获取* param key 键* return 值/public Object get(String key) {return key null ? null : redisTemplate.opsForValue().get(key);}/** 普通缓存放入* param key 键* param value 值* return true成功 false失败/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/** 普通缓存放入并设置时间* param key 键* param value 值* param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期* return true成功 false 失败/public boolean set(String key, Object value, long time) {try {if (time 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/** 递增* param key 键* param delta 要增加几(大于0)/public long incr(String key, long delta) {if (delta 0) {throw new RuntimeException(递增因子必须大于0);}return redisTemplate.opsForValue().increment(key, delta);}/** 递减* param key 键* param delta 要减少几(小于0)/public long decr(String key, long delta) {if (delta 0) {throw new RuntimeException(递减因子必须大于0);}return redisTemplate.opsForValue().increment(key, -delta);}// set/** 根据key获取Set中的所有值* param key 键/public SetObject sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/** 根据value从一个set中查询,是否存在** param key 键* param value 值* return true 存在 false不存在/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {e.printStackTrace();return false;}}/** 将数据放入set缓存** param key 键* param values 值 可以是多个* return 成功个数/public long sSet(String key, Object… values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/** 将set数据放入缓存** param key 键* param time 时间(秒)* param values 值 可以是多个* return 成功个数/public long sSetAndTime(String key, long time, Object… values) {try {Long count redisTemplate.opsForSet().add(key, values);if (time 0) {expire(key, time);}return count;} catch (Exception e) {e.printStackTrace();return 0;}}/** 获取set缓存的长度** param key 键/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/** 移除值为value的** param key 键* param values 值 可以是多个* return 移除的个数/public long setRemove(String key, Object… values) {try {Long count redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}}
模拟场景使用
Slf4j
RequestMapping(/redisLock)
RestController
public class MyRedisLockController {Resourceprivate RedisUtil redisUtil;/** 原子操作redis的数量保证多少线程进来就执行多少次操作** return/GetMapping(/goLock)public String goLock() {//配置锁设置随机uuid进行验证防止误删String uuid UUID.randomUUID().toString();//设置过期时间为10sboolean lock redisUtil.setNx(lock, uuid, 10);if (lock) {log.info(lock成功.{}, uuid);//若已经上锁Object value redisUtil.get(num);//2.1判断num为空returnif (StringUtils.isEmpty(value)) {return key is null;}//2.2有值就转成成intint num Integer.parseInt(value );//2.3把redis的num加1redisUtil.set(num, num);//2.4释放锁del保证锁必须被释放–当业务执行时间小与过期时间时需要释放锁if (uuid.equals((String) redisUtil.get(lock))) {redisUtil.del(lock);return success;} else {return fail;}} else {log.error(lock失败.开始重试{}, uuid);//上锁失败try {Thread.sleep(100);goLock();} catch (InterruptedException e) {e.printStackTrace();}}return done;}/** 模拟实际高并发场景下的** return*/GetMapping(/goShop)public String goShop() {// 首先判断库存量是否还有余量Object value redisUtil.get(num);log.info(当前库存.{}, value);//2.1判断num为空returnif (StringUtils.isEmpty(value)) {log.info(尚未设置库存!);return 尚未设置库存!;}//2.2有值就转成成intint num Integer.parseInt(value );if (num 0) {log.info(已售罄!);return 已售罄;}//配置锁设置随机uuid进行验证防止误删String uuid UUID.randomUUID().toString();//设置过期时间为10sboolean lock redisUtil.setNx(lock, uuid, 10);if (lock) {// 执行一些其他业务操作 并扣减库存…log.info(抢购成功.{}, uuid);//2.3扣减库存redisUtil.set(num, –num);//2.4释放锁del保证锁必须被释放–当业务执行时间小与过期时间时需要释放锁if (uuid.equals((String) redisUtil.get(lock))) {redisUtil.del(lock);return success;} else {return fail;}} else {log.error(抢购失败{}, uuid);}return done;}
}参考资料
Springboot集成Redis——实现分布式锁
- 上一篇: 青岛网站建设运营搜索引擎优化的英文缩写是什么
- 下一篇: 青岛网站开发学校网络营销的五大特点
相关文章
-
青岛网站建设运营搜索引擎优化的英文缩写是什么
青岛网站建设运营搜索引擎优化的英文缩写是什么
- 技术栈
- 2026年03月21日
-
青岛网站建设迅优广州网页设计培训学校
青岛网站建设迅优广州网页设计培训学校
- 技术栈
- 2026年03月21日
-
青岛网站建设维护友情链接如何交换
青岛网站建设维护友情链接如何交换
- 技术栈
- 2026年03月21日
-
青岛网站开发学校网络营销的五大特点
青岛网站开发学校网络营销的五大特点
- 技术栈
- 2026年03月21日
-
青岛网站美工鹤壁做网站优化
青岛网站美工鹤壁做网站优化
- 技术栈
- 2026年03月21日
-
青岛网站上排名p2p网站开发公司
青岛网站上排名p2p网站开发公司
- 技术栈
- 2026年03月21日






