查询重传锁相对于同步块的缺点



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

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

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

Synchronized最简单:您编写Synchronized,仅此而已。对于现代JVM,它的速度相当快,但缺点是它会将所有试图进入synchronization块的线程都挂起,无论它们是否真的需要。如果您过于频繁地使用synchronized,这可能会大大降低多线程的速度,最坏的情况是单线程执行速度会更快。

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

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

在正常情况下,只有当你真正监控它时,你才能通过运行探查器以复杂的方式在前后检查速度来判断速度的差异。

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

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

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

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

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

最新更新