0

我正在阅读 java 中可重入锁和同步块之间的比较。我正在浏览互联网上的各种资源。我发现在同步块上使用可重入锁的一个缺点是,在前一个中,您必须显式使用 try finally 块在 finally 块中获取的锁上调用 unlock 方法,因为您的代码的关键部分可能抛出异常会造成很大的麻烦,如果线程不释放锁,而在后一种情况下,JVM本身会负责在发生异常时释放锁。

我不太相信这个缺点,因为使用 try finally 块并不是什么大不了的事。因为我们已经使用它很长时间了(流关闭等)。有人可以告诉我重入锁相对于同步块的其他一些缺点吗?

4

2 回答 2

0

synchronized对于低或最小争用几乎总是更快,因为它允许 JVM 执行一些优化,例如biased locking,lock elision和其他。以下是它的工作原理的更多细节:

假设某个监视器由线程 A 持有,而线程 B 请求该监视器。在这种情况下,监视器将其状态更改为inflated。简而言之,这意味着所有试图获取此监视器的线程都将在操作系统级别设置等待,这非常昂贵。

现在,如果线程 A 在线程 B 请求之前释放了监视器,则所谓的rebias操作将由廉价的(在现代 CPU 上)compare-and-swap操作执行。

现在让我们来看看ReentrantLock。每个线程调用lock()lockInterruptibly()方法都会导致通过CAS操作完成锁定尝试。

结论:在低争用情况下,更喜欢synchronized. 在高争用情况下,首选ReentrantLock. 对于两者之间的所有情况,很难确定,请考虑执行基准测试以找出哪个解决方案更快。

于 2014-04-20T13:03:37.190 回答
0

ReentrantLock 是针对不同用例的不同工具。虽然您可以将两者用于大多数同步问题(这就是它们的用途),但它们具有不同的优点和缺点。

Synchronized 最多很简单:您编写 synchronized 就可以了。对于现代 JVM,它的速度相当快,但它的缺点是它会暂停所有尝试进入同步块的线程,无论它们是否真的需要。如果您过于频繁地使用同步,这会显着降低多线程的速度,最坏的情况会降低到单线程执行速度更快的程度。

由于线程问题仅在某人正在写入而其他人正在读取/写入相同的数据部分时才会发生,因此程序经常会遇到问题,理论上它们可以在没有同步的情况下运行,因为大多数线程只是读取,但偶尔会出现这样的写入,它强制执行同步块。这就是锁的用途:您可以更好地控制实际同步的时间。

基本的 ReentrantLock 允许 - 除了构造函数中的公平参数之外 - 您可以决定何时释放锁,并且您可以在多个点执行此操作,因此何时最适合您。它的其他变体如 ReentrantReadWriteLock 允许您进行许多非同步读取,除非有写入。缺点是这是在 Java 代码中解决的,这使得它明显比“本机”同步块慢。也就是说:只有在您知道使用此锁的优化增益大于损失时,您才应该使用它。

在正常情况下,如果您实际监控速度,您只能通过运行分析器以复杂的方式检查前后速度的差异。

于 2014-04-20T11:32:34.537 回答