可重入锁允许一个线程多次获取同一把锁,避免线程自身被锁死。1.reentrantlock基于aqs实现,通过cas操作和fifo队列管理锁的获取与释放;2.可重入性通过判断当前线程是否为锁持有者实现,state值记录重入次数;3.释放锁时减1,state为0才唤醒等待线程;4.可重入性在一定程度上避免死锁,但无法完全解决;5.公平锁按请求顺序分配,非公平锁允许插队,性能更高但可能导致饥饿;6.选择reentrantlock可获得更灵活控制、公平锁、中断响应等功能,而synchronized则适合简单场景、自动释放锁且可能优化性能。
可重入锁,简单来说,就是允许一个线程多次获取同一把锁。这在Java中非常重要,尤其是在复杂的并发场景下,它避免了自己把自己锁死的情况,让代码更灵活。
ReentrantLock的实现原理
ReentrantLock的核心是AQS(AbstractQueuedSynchronizer)。AQS维护了一个同步状态(state)和一个FIFO的等待队列。
立即学习“Java免费学习笔记(深入)”;
获取锁: 当一个线程尝试获取锁时,首先会尝试使用CAS(Compare and Swap)原子操作将state从0变为1。如果成功,则该线程获取锁,并将锁的持有者设置为当前线程。如果state不为0,则检查当前线程是否为锁的持有者。如果是,则将state加1,表示重入次数加1。如果CAS失败,并且当前线程不是锁的持有者,则该线程会被放入AQS的等待队列中,等待被唤醒。
释放锁: 当线程释放锁时,首先检查当前线程是否为锁的持有者。如果不是,则抛出异常。如果是,则将state减1。如果state变为0,则表示锁完全释放,会唤醒等待队列中的一个线程,让其尝试获取锁。
可重入性: ReentrantLock之所以可重入,是因为它在获取锁的时候,会检查当前线程是否为锁的持有者。如果是,则允许重入,并将state加1。这样,同一个线程就可以多次获取同一个锁,而不会被阻塞。
ReentrantLock如何避免死锁?
死锁往往是因为多个线程互相持有对方需要的资源,导致大家都无法继续执行。ReentrantLock的可重入性,在一定程度上避免了死锁的发生。例如,一个线程在已经持有锁的情况下,如果需要再次获取该锁,由于ReentrantLock的可重入性,它可以直接获取,而不会被阻塞。
然而,仅仅依靠ReentrantLock的可重入性并不能完全避免死锁。仍然需要注意锁的获取顺序,以及避免循环依赖等问题。
公平锁与非公平锁的区别?
ReentrantLock可以配置为公平锁或非公平锁。
公平锁: 按照线程请求锁的顺序来分配锁。也就是说,等待队列中最先进入的线程会优先获取锁。公平锁保证了所有线程都有机会获取锁,避免了某些线程长时间饥饿的情况。但公平锁的性能相对较低,因为需要维护等待队列的顺序。
非公平锁: 允许线程“插队”。也就是说,当锁被释放时,如果有线程正在尝试获取锁,它可以直接获取锁,而不需要等待进入等待队列。非公平锁的性能相对较高,因为减少了线程切换的开销。但非公平锁可能导致某些线程长时间饥饿。
选择公平锁还是非公平锁,取决于具体的应用场景。如果对公平性要求较高,可以选择公平锁。如果对性能要求较高,可以选择非公平锁。大多数情况下,非公平锁是更好的选择。
如何选择ReentrantLock而不是synchronized?
synchronized是Java内置的同步机制,而ReentrantLock是一个类,提供了更灵活的锁控制。
选择ReentrantLock的情况:
选择synchronized的情况:
总的来说,synchronized更适合简单的同步场景,而ReentrantLock更适合复杂的同步场景。需要根据具体情况进行选择。
以上就是Java中可重入锁的作用 解析ReentrantLock的实现原理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号