锁重试与看门狗机制
锁重试与看门狗机制 抢锁过程中,获得当前线程,通过tryAcquire进行抢锁,该抢锁逻辑和之前逻辑相同 1、先判断当前这把锁是否存在,如果不存在,插入一把锁,返回null 2、判断当前这把锁是否是属于当前线程,如果是,则返回null 所以如果返回是null,则代表着当前这哥们已经抢锁完毕,或者可重入完毕,但是如果以上两个条件都不满足,则进入到第三个条件,返回的是锁的失效时间,有个while( true) 会再次进行tryAcquire进行抢锁 123456long threadId = Thread.currentThread().getId();Long ttl = tryAcquire(-1, leaseTime, unit, threadId);// lock acquiredif (ttl == null) { return;} 接下来会有一个条件分支,因为lock方法有重载方法,一个是带参数,一个是不带参数,如果带带参数传入的值是-1,如果传入参数,则leaseTime是他本身,所以如果传入了参数,此时leaseTime != -1...
Redisson的可重入锁原理
Redisson的可重入锁原理在Lock锁中,他是借助于底层的一个voaltile的一个state变量来记录重入的状态的,比如当前没有人持有这把锁,那么state=0,假如有人持有这把锁,那么state=1,如果持有这把锁的人再次持有这把锁,那么state就会+1 ,如果是对于synchronized而言,他在c语言代码中会有一个count,原理和state类似,也是重入一次就加一,释放一次就-1 ,直到减少成0 时,表示当前这把锁没有被人持有。 在redission中,我们的也支持可重入锁 在分布式锁中,他采用hash结构用来存储锁,其中大key表示表示这把锁是否存在,在这是userID,用小key表示当前这把锁被哪个线程持有,在这是threadId,所以接下来我们一起分析一下当前的这个lua表达式 这个地方一共有3个参数 KEYS[1] : 锁名称 ARGV[1]: 锁失效时间 ARGV[2]: id + “:” + threadId; 锁的小key exists: 判断数据是否存在 ...
Redisson - 初始配置
Redisson - 初始配置基于setnx实现的分布式锁存在下面的问题: 重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。 不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。 超时释放:我们在加锁时增加了过期时间,这样的我们可以防止死锁,但是如果卡顿的时间超长,虽然我们采用了lua表达式防止删锁的时候,误删别人的锁,但是毕竟没有锁住,有安全隐患 主从一致性: 如果Redis提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步过去之前,主机宕机了,就会出现死锁问题。 1,添加依赖 12345<dependency> ...
分布式锁
分布式锁常见的三种: 基于Redis的分布式锁 在高并发的场景下,阻塞式的锁很容易耗光系统的性能。 误删分布式锁 12345678910111213141516171819202122232425262728293031323334353637private StringRedisTemplate stringRedisTemplate; private String name; private static final String ID_PREFIX= UUID.randomUUID().toString(true)+"-"; private static final String KEY_PREFIX="lock:"; public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) { this.stringRedisTemplate = stringRedisTemplate; ...
加锁时机
加锁时机1,在方法上加锁123456789101112131415161718192021222324252627282930313233@Transactionalpublic synchronized Result createVoucherOrder(Long voucherId) { //一人一单 Long userId = UserHolder.getUser().getId(); int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count(); if(count>0){ return Result.fail("用户已经购买过一次"); } //6,创建订单 VoucherOrder voucherOrder = new VoucherOrder(); long orderId =...
基于逻辑过期进行缓存预热,解决缓存击穿问题
基于逻辑过期进行缓存预热,解决缓存击穿问题大体思路: 所有热点数据会提前存入redis,如果缓存未命中,说明不是热点数据,可以直接返回空 缓存穿透是有大量不存在数据访问redis,redis未命中然后去访问数据库,就造成了缓存穿透。 这里我们只针对的热点数据,操作的是缓存,要判断的也只是数据是否过期,过期就另开一个线程重建缓存,在这个重建缓存的时间内,其他并发线程访问缓存,返回的是过期的数据,这个树据在缓存中并没有真的过期,只是存入了一个过期时间,后面判断就是根据这个过期时间进行的,所以说是逻辑过期,保证了可用性。 实现 1,为原来的实体类添加一个字段:expireTime,这里采用的是装饰器模式,另建了一个类,当然也可以继承 12345@Datapublic class RedisData { private LocalDateTime expireTime; private Object data;} data中可以存原来的实体类 2,可以在测试类中进行缓存预热 12345678910111213//缓存预热...
windows 常用查端口命令
windows 常用查端口命令1,查看端口占用情况 1netstat -ano 2,查看某个端口被占用的情况 1netstat -ano | findstr xxxx //xxxx为查询的端口号 3,查看某个状态的端口 1netstat -ano | findstr xxxx //xxxx为查询的端口状态 4,查看使用指定端口的应用程序 1tasklist | findstr xxxx //xxxx指的是pid 5,结束指定进程 12taskkill /pid xxxx -t -f //xxxx指的是pid或者:taskkill /f /t /im QQ.exe
基于互斥锁方式解决缓存击穿问题
基于互斥锁方式解决缓存击穿问题大体思路: 参考代码: 123456789101112@Override public Result queryById(Long id) { //互斥锁解决缓存击穿,缓存空对象解决缓存穿透 Shop shop = queryWithMutex(id); if(shop==null){ return Result.fail("店铺信息不存在"); } return Result.ok(shop); } 关键代码: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980//互斥锁解决缓存击穿问题 public Shop queryWithMutex(Long...
通过缓存空对象解决缓存穿透问题
通过缓存空对象解决缓存穿透问题123456789101112@Override public Result queryById(Long id) { //通过缓存空值,解决缓存穿透问题 Shop shop = queryWithPassThrough(id); if(shop==null){ return Result.fail("店铺信息不存在"); } return Result.ok(shop); } 1234567891011121314151617181920212223242526272829303132333435363738394041//缓存空对象解决缓存穿透问题 public Shop queryWithPassThrough(Long id){ //1,从redis中查询商铺缓存 String shopJson =...
缓存常见问题
...






