在java中使用读写锁发现的问题

在java中使用读写锁,有两种方式:
1、如果服务器是单节点,可以使用jdk自带的ReentrantReadWriteLock(new ReentrantReadWriteLock())
2、如果服务器是多节点,可以使用redission分布式锁(redissonClient.getReadWriteLock(key))

读写锁有以下几种特性:
1、读写互斥,写写互斥,读读不互斥
2、可以降级锁(先获取写锁,然后再获取读锁,再释放写锁),但不能升级锁(先获取读锁,然后再获取写锁,再释放读锁),升级锁会卡在获取写锁那一步(写锁在等待上一步获取的读锁释放)

为什么可以降级锁,而不能升级锁:
因为降级锁是从写锁降级为读锁,此时,同一时间拿到写锁的只有一个线程,可以直接降级为读锁,不会造成冲突,而升级锁是从读锁升级为写锁,此时,同一时间拿到读锁的可能会有多个线程,会造成冲突

使用redission的读写锁时发现一些问题:
1、降级锁时,释放写锁后,不再自动续期了,如果程序处理时间较长,还没有释放读锁,但是锁的过期时间到了并且没有其他线程在占用读锁就会自动释放锁,此时,其他线程的写锁也可以获取了,违反了读写互斥原则。这个问题的原因是,降级锁先获取的写锁,在获取写锁的同时,会新建一个Timeout延迟10秒后续期,如果没有取消续期并且写锁的LockName存在则续期成功,并开启下一个Timeout延迟10秒后续期,不断的轮询,如果写锁的LockName不存在则续期失败,不再开启下一个Timeout了,自动续期结束。所以,当写锁释放的同时,就会删除写锁的LockName(读锁和写锁的LockName是不相同的),下次续期时就会失败,然后就不再自动续期了,详情参考:org.redisson.RedissonLock.renewExpiration()
2、降级锁时,在释放写锁的时候,没有发布通知,如果在释放写锁之前,已经有其他线程在等待获取读锁,那么在释放写锁后,其他等待获取读锁的线程不能马上获取到读锁,还会继续等待,直到本线程的读锁程序手动释放或超时自动释放(上面已经讲了,降级锁释放写锁后不会自动续期,所以会存在程序还没有手动释放读锁而超时自动释放的情况),其他线程才能获取到读锁。详情参考:org.redisson.RedissonWriteLock.unlockInnerAsync(long threadId)

标签: 在java中使用读写锁发现的问题

添加新评论