修复混乱代码中的死锁

时间:2012-04-06 12:23:22

标签: java multithreading synchronization locking

我正在修改一些非常复杂的代码,我需要在此基础上添加自己的同步。

但是,现有代码有大约十几个(如果不是更多)不同的锁,我的​​代码需要调用它的一些方法。我真的不知道获取锁的顺序,也无法真正控制它。

所以,我的问题是,如果我用一个锁替换所有不同的锁会怎么样?。除了牺牲粒度,还有其他问题我应该注意吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

如果你更改了所有synchronized块(和方法),所有其他阻塞结构,我认为你应该没问题 - 最糟糕的情况是,你的应用程序退化为拥有串行执行。但如果你只改变其中一些,你就会陷入僵局。考虑两个线程各自获取多个锁的情况:

Thread 1:
    synchronized A
        synchronized B

Thread 2:
    synchronized B
        synchronized C

此处没有死锁风险,但如果您使用新的常用锁替换AC(但不是B),那么您将拥有:

Thread 1:
    synchronized L
        synchronized B

Thread 2:
    synchronized B
        synchronized L

...这是典型的死锁案例。

考虑另一个场景,其中锁本身不提供死锁,而是像CountDownLatch一样死锁一个阻塞类:

Thread 1:
    synchronized A
        latch L.countDown()

Thread 2:
    synchronized B
        latch L.await()

在这种情况下,更改两个synchronized块以锁定公共锁定不会导致它们之间的死锁,但如果线程2首先获得锁定将导致死锁:它将等待锁存器的countDown,将永远不会到来,因为线程1在其synchronized入口点被阻止。此示例也适用于其他阻塞结构:信号量,阻塞队列等。

答案 1 :(得分:1)

我认为没有任何替代品可以正确分析代码。它之所以可怕,可能是因为其他所有不得不对其进行修改的人都做了与你完全相同的事情,并且在适当的分析中做出了抨击。

编写一些应该澄清锁定的日志代码应该相当简单。一旦你可以拆开图层并拥有清晰的图像,用一个现代锁替换整个批次应该相对简单,例如ReadWriteLock或类似。

您可能会发现借此机会添加一些测试代码以便以受控方式执行日志记录非常有用。任何复杂代码都是非常有用的补充。

答案 2 :(得分:0)

很难说没有看到代码会发生什么。 您可能遇到死锁问题,如果在其中一个锁内,它会尝试抓住另一个锁。此外,它还可以在等待获取单个锁定与多个锁定时降低应用程序的速度。