我正在阅读java中的重入锁和同步块之间的比较。我正在浏览互联网上的各种资源。我发现使用Reentrant锁定同步块的一个缺点是,在前一个版本中,您必须显式使用try finally块来对finally块中获取的锁调用unlock方法,因为您的关键代码段可能可能是如果线程没有释放锁,则抛出异常会导致大麻烦。在后者中,JVM本身负责在异常情况下释放锁。
我不太相信这个缺点,因为使用try finally block并不是什么大问题。因为我们已经长时间使用它(流关闭等)。有人可以告诉我重新锁定同步块的其他一些缺点吗?
答案 0 :(得分:0)
ReentrantLock是针对不同用例的不同工具。虽然您可以同时使用它们(这就是它们的用途),但它们有不同的优点和缺点。
同步最简单:你写同步,就是这样。使用现代JVM,它的速度很快,但缺点是它会尝试进入同步块的所有线程都保持不变,无论它们是否真正需要。如果经常使用synchronized,这可以大大降低多线程的速度,最糟糕的情况是单线程执行速度更快。
由于线程问题只发生在某人正在编写而其他人正在读/写相同的数据部分时,程序经常遇到问题,理论上它们可以在没有同步的情况下运行,因为大多数线程只读,但是有一个偶尔写入,强制执行synchronized块。这就是Locks的用途:您可以更好地控制实际同步的时间。
基本的ReentrantLock允许 - 除了构造函数中的公平参数 - 您可以决定何时释放锁定,并且您可以在多个点执行此操作,因此最适合您。像ReentrantReadWriteLock这样的其他变体允许您有许多未同步的读取,除非有写入。缺点是这在Java代码中得到了解决,这使得它明显慢于“本机”同步块。这就是说:你应该只使用它,如果你知道使用这个锁的优化收益大于损失。
在正常情况下,你只能通过运行探查器以复杂的方式检查前后的速度来判断速度的差异。
答案 1 :(得分:0)
synchronized
几乎总是更快,因为它允许JVM执行某些优化,例如biased locking
,lock elision
等。以下是其工作原理:
假设某个监视器由线程A持有,而线程B请求该监视器。在这种情况下,监视器将其状态更改为inflated
。简而言之,这意味着所有尝试获取此监视器的线程都将在OS级别进行等待设置,这非常昂贵。
现在,如果线程A在线程B请求它之前释放了监视器,则所谓的rebias
操作将由廉价(在现代CPU上)compare-and-swap
操作执行。
现在让我们来看看ReentrantLock
。每个线程调用lock()
或lockInterruptibly()
方法导致通过CAS
操作完成锁定尝试。
结论:在低争用的情况下,更喜欢synchronized
。在高争用的情况下,更喜欢ReentrantLock
。对于所有情况之间,很难肯定地说,考虑执行基准来找出哪个解决方案更快。