【新梦想老师分享】分布式锁的正确”姿势”

一、概述


在如今高并发,分布式大行其道的今天,如果你还只会单体项目,那未免也太落伍了。撇开技术落伍,受人耻笑外(脸皮厚的人根本不在乎耻笑),更为现实的问题是:如果你是刚进入职场的新人,即将面临找工作,估计连面试机会都没有,如果你是已经在职的人士,不知晓分布式的各种成人姿势,那你也只有在公司任人玩弄的份。说到分布式这么重要,那今天我作为一个潜伏它圈多年的老将,跟大家分享下分布式下的分布式锁的各种成人姿势,注意是成人哦,未成年人勿入。


二,问题现场还原——秒杀系统下单功能


1。mysql数据库有2张表:股票(库存表),stock_order(订单表)。


2。后台通过弹簧引导构建下单的业务接口(下单流程=查库存——下单——减库存)。


3。打开浏览器正常业务流程再现,刷新多少次,卖出多少份皮蛋粥,没毛病。




4。使用压测工具(ab/jemter/loaderrunner)进行压力测试ab - n 100 - c 100 http://127.0.0.1:8080 second-kill3/技能/订单/123456


5。再次打开浏览器查看库存




各位看官,看到这个结果是不是有一种蛋碎一地的感觉! ! !怎么可能10000份皮蛋粥可以卖出(9989 + 109),如果你感觉奇怪,那说明你的技术已经了。好了到此场景还原就到此结束。接下来给各位介绍下解决这种问题的各种姿势。


三,姿势一:同步


了解多线程的同学肯定会想的到,并发线程安全问题,可以用jdk同步工具同步解决。正确的说法给大家更正下,叫做数据库丢失更新。能想到这里的我算你有点社会实践姿势,但是效果如何,请看:


1。给下单方法加同步,做同步。




2。继续压力测试


ab - n 100 - c 100 http://127.0.0.1:8080 second-kill3/技能/订单/123456




3。同步姿势总结:


1)是一种解决方案。


2)同步无法实现细粒度的锁。


在下单的方法中加同步会将所有商品下单都做同步,如果另外一件商品并没有很高并发量。也会导致很请求很慢,锁的粒度太大。


3)只适合单点情况。(而现实是高并发,分布式集群当道)


四,姿势二:分布式锁


接下来是我们的主角:分布式锁登场了。


分布式锁的三种实现方式:数据库分布式锁,复述,分布式锁,动物园管理员分布式锁。今天打算给大家介绍下复述分布式锁的实现方式。


1。安装复述,【不知道怎么安装的,请咨询我的官方秘书度娘】


2。maven工程中导入spring-redis依赖。


org.springframework。启动


spring-boot-starter-data-redis


3。编写redisLock实现加锁与解锁


org.springframework。引导spring-boot-starter-data-redis


3。编写redisLock实现加锁与解锁


/* *


加锁


@param关键

@param价值当前时间+超时时间


@return


*/


公共静态逻辑锁(字符串,字符串值){


//setIfAbsent=setNX如果不存在,就设置值并返回真,否返回假


//1,加锁成功如果(redisTemplate.opsForValue () .setIfAbsent(键,值)){返回true;}


//2,避免死锁(线程1加锁成功,结果在解锁前出现异常,没有解锁,导致死锁)


//2.1获取过期时间StringcurrentValue=https://www.yisu.com/zixun/redisTemplate.opsForValue () . get(关键);


//2.2判断过期时间于当前时间的关系


如果(! StringUtils.isEmpty (currentValue)


,, Long.parseLong (currentValue) & lt; System.currentTimeMillis()){字符串oldValue=https://www.yisu.com/zixun/redisTemplate.opsForValue () .getAndSet(键,值);如果(! StringUtils.isEmpty oldValue &&oldValue.equals (currentValue)){返回true;


}


}


//3,加锁失败t2结束返回假


返回false;


}


/* *


解锁


@param关键

@param值


*/


公共空间解锁(字符串,字符串值){

【新梦想老师分享】分布式锁的正确”姿势”