目录
前沿:
那么我们如何解决分布式项目中 线程安全问题呢 ?
redis 解决分布式项目中 线程安全问题
Lua脚本保证原子性:
可重入锁:
Redisson的实现分布式锁 方案
Redisson -公平锁:
Redisson -联锁:
Redisson -红锁:
Redisson -读写锁:
Redisson -信号量:
Redisson -可过期性信号量:
Redisson -闭锁:
结尾:其实在解决分布式项目中线程安全问题 不只这一种,还有其它的方案
前沿:
在传统单体项目中,没有对项目进行集群的情况下,我们保证线程安全,可以利用到JDK(jvm)里面自带两把锁,Lock锁,Synchronized锁。保证单体项目中线程安全问题。
在项目做了集群之后,部署到其他机器上的时候,这个时候是跨了jvm虚拟机的,JDK(jvm)自带的锁 就不能处理到其他机器上的线程
那么我们如何解决分布式项目中 线程安全问题呢 ?
基于上面的问题 这个时候我们可以把 锁整成为一个公共的服务或者中间件。线程需要拿到锁之后才可以执行相应的服务。 这样就可以保证线程安全性
redis 解决分布式项目中 线程安全问题
思路:在解决分布式事务中 可以用redis实现 ,因为redis在设置值和获取值是单线程的 ,单线程天然就不会有线程安全问题,可以先把锁存到redis里面。如果一个线程能从redis里面拿到锁,那就可以去访问对应的服务。。redis在进行数据持久化这些,是多线程的。
具体实现:假设现在有三个线程 A B C ,这三个线程属于不同的机器上。我们把三个线程的key都假设一样,value值为锁,此时三个线程都是进来,由于redis的key是唯一的,那么此时只会有一个线程把锁存入成功,假设现在是A存入锁成功了,那么A现在可以去执行对应的服务。A执行完了后,把key删除掉。其他线程又开始存,假设现在是B线程把锁存入了,刚刚执行到中途,这时候Redis宕机了,会导致其他线程使用相同key存入不成功,一直执行不到业务代码,照成死锁。(并非这一种情况,还有其他概率,误删其他线程的key等)
Lua脚本保证原子性:
基于上面的说的,也产生了很多不可避免的概率问题:误删其他线程的key,死锁产生。
基于误删情况,这时候 Lua脚本可以保证原子性 判断是不是自己的锁(UUID)和删除锁是一组操作 。
可重入锁:
上面的情况,还有极端情况,就是获取锁的时候没有成功,也就还没有进入到if判断里面,线程想当就是白跑一趟,这是时候,就会可以使用 到可重入锁,简单理解就是一个线程在进来的时候是失败了,这时候让这个线程等待片刻之后再次尝试获取锁
Redisson的实现分布式锁 方案
基于上面的情况,redis实现的分布式锁,我们开发人员考虑的细节是比较多的,这时候有一款 Redisson的工具,完美帮我们解决了这些细节问题,其实就是对redis的封装
用法:导入对应依赖,Redisson链接到redis,链接成功就可以使用Redisson里面的api操作redis了
Redisson里面提供了一个线程,作用类似看门狗,当业务代码执行完成后,会根据默认的时间删除,如果在默认时间没有执行,会加长时间。如果有设置过期时间,直接把设定的过期时间作为锁的过期时间,然后使用Lua脚本获取锁,没获取到锁的线程会while自旋重入不停地尝试获取锁
Redisson -公平锁:
它保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。
Redisson -联锁:
顾名思义联合一起锁 。才算成功 类似于王者荣耀里,大家都点击确认才可以选英雄。
Redisson -
红锁:
大部分节点上加锁成功才算成功,如果没有获取到成功,则把部分已锁的释放掉。
Redisson -读写锁:
顾名思义读锁和写锁。如果如果是读锁,一个在读,其他人也是可以读的。但是有一个人在写,其他人必须要等这个人写完,才能去写。简单理解就是我在写数据的时候,你是不能来读的。
Redisson -信号量:
简单理解就是一Reids里面保存的一个数字,可以实现原子性的加减
操作:获取到信号量对象,把数字存入 信号量里面取个名字,后面通过名字取。就算很多个线程来,也只会一个线程完整操作成功。 秒杀的商品可以数量,可以放到信号量实现
Redisson -可过期性信号量:
就是在信号量的基础上,设置一个过期时间
Redisson -闭锁:
闭锁可以实现多个线程都执行完才是完成的效果,否则闭锁会等待。理解:打排位的时候,正常情况下,都是大家加载到100后之后,才一起进入到游戏里面。
结尾:其实在解决分布式项目中线程安全问题 不只这一种,还有其它的方案
例如本地消息表,zookeeper 等。下一篇会写关于目前最流行的分布式解决方案--zookeeper



