java - 了解锁类与同步

标签 java multithreading locking

在《Java 并发实践》中,我提出了避免死锁的技术。他建议当我们需要获取多个锁来保证一致性时使用tryLock()。如下:

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

相反,我们最好使用这个:

public void m(MyObject o1, MyObject o2){
    while(true){
        if(o1.lock.tryLock(){
             try{
                 if(o2.lock.tryLock(){ 
                     try{
                          //...
                     } finally {
                          o2.lock.unlock();
                     }
                 }
            } finally { 
                  o2.lock.unlock()
            }
        }
    }
}

现在他走了:

This technique works only when the two locks are acquired together; if multiple locks are acquired due to nesting of method calls you cannot just realease the outer lock, even if you know you hold it.

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

最佳答案

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

理论上,您仍然可以在嵌套方法调用中使用此技术,但它很快就会变得笨拙。让我们考虑一个简单的示例,其中您尝试在方法 foo(Lock lock) 中获取一些锁,如果成功,则在几个堆栈帧之后您尝试在方法 中获取另一个锁栏(锁锁).

  • 如果您的两个方法都使用 while (true) 直到它们最终设法获得锁,那么如果一个线程在foo(),另一个在 foo() 中获得了 B,现在两者都在 bar() 中无休止地旋转,尝试获取对方的锁。
  • 如果只在foo()方法中循环,并在获取锁不成功时从bar()返回,也许可以避免死锁,但是现在:
    • foo()bar() 紧密耦合
    • 根据 bar() 调用的具体时间,获取第一个锁和获取第二个锁之间的漏洞窗口可能会非常大
    • 您需要从foo()中的循环开始重新计算整个分支
    • 目标代码路径变得非常难以遵循并且很容易被破坏
  • 如果您使用定时锁,您仍然会遇到上述一些问题,您需要处理 InterruptedException,并且需要决定如何循环。
    • 一般技术已经很容易生成大量 IllegalMonitorStateException,这不太好

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

附注经过几次尝试,我得到了 tryLock() 和定时 tryLock(long time, TimeUnit unit) 方法来使用上述两种方法,两种方法锁定方案。不太漂亮,而且我可以很容易地看出 protected 部分的简单更改会如何破坏整个方案或使其变得过于复杂。

关于java - 了解锁类与同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36675945/

相关文章:

java - 强制执行打印顺序,但线程在一次迭代后彼此等待

java - Java中的非阻塞堆栈

mysql - 是否可以为 MYSQL 中的特定用户设置 TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

python - 使用 Python(ubuntu) 检测工作站/系统屏幕锁定

javascript - 为什么 reactjs 中的 setState 是 Async 而不是 Sync?

java - 在 Docker File 中添加容器启动时启动的脚本

java - 使用 JGit 列出当前分支中的所有标签

java - 按数据范围和另一个过滤器搜索

Python:锁定文件

java - Android 音频流的 UDP 或 TCP