我正在修改一些非常复杂的代码,我需要在此基础上添加自己的同步。
但是,现有代码有大约十几个(如果不是更多)不同的锁,我的代码需要调用它的一些方法。我真的不知道获取锁的顺序,也无法真正控制它。
所以,我的问题是,如果我用一个锁替换所有不同的锁会发生什么?。除了牺牲粒度之外,还有其他我应该注意的问题吗?
谢谢!
我正在修改一些非常复杂的代码,我需要在此基础上添加自己的同步。
但是,现有代码有大约十几个(如果不是更多)不同的锁,我的代码需要调用它的一些方法。我真的不知道获取锁的顺序,也无法真正控制它。
所以,我的问题是,如果我用一个锁替换所有不同的锁会发生什么?。除了牺牲粒度之外,还有其他我应该注意的问题吗?
谢谢!
如果您更改所有synchronized
块(和方法)以及所有其他阻塞结构,我认为您应该没问题 - 最坏的情况是,您的应用程序退化为具有串行执行。但是如果你只改变其中的一部分,你可能会陷入僵局。考虑两个线程各自获取多个锁的场景:
Thread 1:
synchronized A
synchronized B
Thread 2:
synchronized B
synchronized C
这里没有死锁的风险,但是如果你用新的普通锁替换A
and C
(但不是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 先获得锁,则会导致死锁:它将等待锁存器的倒计时,因为线程 1 被阻塞,所以永远不会出现在其synchronized
入口点。这个例子也适用于其他阻塞结构:信号量、阻塞队列等。
我认为没有任何替代品可以正确分析代码。它可怕的原因可能是因为其他不得不修改它的人都做了和你一样的事情,并且对正确的分析犹豫不决。
编写一些应该阐明锁定的日志记录代码应该相当简单。ReadWriteLock
一旦您可以拆开层并获得清晰的图片,用一把现代锁(例如a或类似锁)替换整个地块应该相对简单。
您可能会发现利用这个机会添加一些测试代码来以受控方式锻炼您的日志记录很有用。对任何复杂代码都非常有用的补充。
如果没有看到代码,很难确切地说会发生什么。如果在其中一个锁内,它试图抓住另一个锁,您可能会遇到死锁问题。此外,在等待获取单个锁与多个锁时,它可能会减慢应用程序的速度。