了解锁类与同步

时间:2016-04-17 11:33:46

标签: java multithreading locking

在Java Concurrency In Practice中,我提出了避免死锁的技术。当我们需要获取多个锁以确保一致性时,他建议获得使用$scope.$on('server_error', function(event, error) { console.log('handling server_error', error); }); 。如下:

tryLock()

相反,我们最好使用它:

public void m(MyObject o1, MyObject o2){
    synchronized(o1){
        synchornized(o2){
            //...
        }
    }
}

现在他去了:

  

此技术仅在同时获取两个锁时才有效;如果   由于您无法嵌套方法调用,因此获取了多个锁   只要释放外锁,即使你知道你持有它。

这不是很明显。为什么我们不能在方法中调用方法时使用它?你能举个例子吗?

1 个答案:

答案 0 :(得分:2)

我刚刚查看了本书,发现引用的语句是在定时锁定的情况下进行的(使用tryLock(long time, TimeUnit unit)),但我认为它也适用于您的tryLock()示例。 / p>

从理论上讲,你仍然可以在嵌套方法调用中使用这种技术,但它很快就变得难以处理。让我们考虑一个简单的例子,你尝试在方法foo(Lock lock)中获得一些锁,如果你成功了,那么你可以尝试在方法bar(Lock lock)中获得另一个锁。

  • 如果你的两个方法都使用while (true),直到他们最终设法获得锁定,那么如果一个线程在A中获得foo(),另一个已获得锁定,则很容易陷入死锁B中的foo(),现在两者都在bar()无休止地旋转,试图获取对方的锁。
  • 如果仅在foo()方法中循环并在锁定获取失败时从bar()返回,则可能可以避免死锁,但现在:
    • foo()bar()紧密相连
    • 取决于稍后调用多少bar(),获取第一个锁和获取第二个锁之间的漏洞窗口可能非常大
    • 您需要从foo()
    • 中的循环开始重新计算整个分支
    • 目标代码路径变得非常难以理解
  • 如果你使用定时锁,你仍然会遇到上述一些问题,你需要处理InterruptedException,你需要决定你想要循环的方式。
    • 一般技术已经容易产生一些IllegalMonitorStateException s,这不是太好了

如果您经常获取相同的锁定子集并使用相同的资源子集,您可能需要考虑锁定粗化(将一些锁定合在一起)或重新定义资源保护策略,以便您不需要在单个工作流程中获得多级锁定。

P.S。经过几次尝试,我得到了tryLock()和定时tryLock(long time, TimeUnit unit)方法,可以使用上述双方法双锁方案。不漂亮,我可以很容易地看到受保护部分的简单更改会破坏整个方案还是使其过于复杂。