我有两个独立的类,两个类函数相互调用。我在两个类函数上都设置了同步块,但是coverity给出了有关LOCK_INVERSION和LOCK_ORDER的错误,否则可能导致死锁,不确定。
在我的生产代码上,我在coverity中得到了下面的错误。
获取锁的“锁名”与在其他地方建立的锁顺序冲突。
示例示例:
package multithreading;
public class Test1 implements Runnable {
private static Test1 instance = null;
public static synchronized Test1 getInstance() {
if (instance == null) {
instance = new Test1();
return instance;
} else {
return instance;
}
}
private Object lock = new Object();
public void sendUpdate() {
synchronized (lock) {
try {
Thread.sleep(3000l);
System.out.println(getClass().getSimpleName() + "sendUpdate");
Test2.getInstance().send();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void sendUpdate1() {
synchronized (lock) {
try {
Thread.sleep(3000l);
System.out.println(getClass().getSimpleName() + "sendUpdate1");
Test2.getInstance().send();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t = new Thread(Test1.getInstance());
t.start();
}
@Override
public void run() {
while (true) {
this.sendUpdate();
}
}
}
package multithreading;
public class Test2 implements Runnable {
private static Object object = new Object();
private static Test2 instance = null;
public static synchronized Test2 getInstance() {
if (instance == null) {
instance = new Test2();
return instance;
} else {
return instance;
}
}
public void send1() {
synchronized (object) {
try {
Thread.sleep(3000l);
System.out.println(getClass().getSimpleName() + "send1");
Test1.getInstance().sendUpdate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void send() {
synchronized (object) {
try {
Thread.sleep(3000l);
System.out.println(getClass().getSimpleName() + "send");
Test1.getInstance().sendUpdate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t = new Thread(Test2.getInstance());
t.start();
}
@Override
public void run() {
while (true) {
Test2.getInstance().send1();
}
}
}Analysis summary report:
------------------------
Files analyzed : 2 Total
Java (without build) : 2
Total LoC input to cov-analyze : 90
Functions analyzed : 15
Paths analyzed : 71
Time taken by analysis : 00:00:18
Defect occurrences found : 1 LOCK_INVERSION我认为这可能导致死锁问题,但我想了解如何在两个相互调用函数的独立类中基本上处理同步。
我们如何维持两个类之间的锁顺序?我应该使用基于ENUM的共享锁,但我有点担心性能,或者还有其他方法来处理这种情况?
发布于 2022-04-09 12:50:54
Coverity报告的原因是代码包含潜在的死锁错误。具体地说:
Test1.sendUpdate()收购Test1.lock,然后调用Test2.send(),后者收购Test2.object。同时,Test2.send()获得Test2.object,然后调用Test1.sendUpdate(),后者获得Test1.lock.如果线程T1与另一个线程T2执行Test2.send()同时执行Test2.send(),则这种排序是可能的:
Test1.lock.
Test2.object.
Test1.lock,阻塞是因为它已经被T1持有,
Test2.object,阻塞是因为T2已经持有。
F 231
当单个线程必须同时持有多个锁时,防止死锁的典型方法是确保获取锁的顺序始终一致。在这里,这意味着要么Test1.lock总是先获得,要么Test2.object总是先获得。
在代码中这样做的一种方法是更改Test2.send(),以便它首先获得Test1.lock:
public void send() { // in class Test2
Test1 test1 = Test1.getInstance();
synchronized (test1.lock) { // Test1.lock first <-- ADDED
synchronized (object) { // Test2.object second
try {
... // same code as before
test1.sendUpdate();
...
}
}
}
}在send()内部,对sendUpdate()的调用将第二次收购Test1.lock。这是可以的,因为Java中的锁是recursive。
上面的代码要求Test1.lock是public,在本例中可能是最简单的修复。当然,如果公共数据成员是一个关注点,那么就很容易公开一个getter。
或者,您可以用保护这两个类的单个锁替换现有的一对锁。这样可以避免死锁,但可以减少并发执行的机会。如果不知道它到底在做什么(这可能是一个新问题的主题),那么这是否会对应用程序性能产生重大影响是不可能的。
https://stackoverflow.com/questions/71805348
复制相似问题