问题描述
我有一个如下格式的java文件
class Demo {
private static Logger logger;
...
...
public static void main(){
// code to initialize logger
demoMethod()
}
private int demoMethod {
synchronized (tmpObj) {
...
helperMethod(tmpParam);
// some more logic of demoMethod related to file reading
logger.log("message from demo method");
...
//there is more logic that involves more loggers
}
}
private int helperMethod(int tmp){
//some logic of helperMethod related to Files
if(condition) {
logger.log("message from helperMethod");
}
return 1;
}
}
从上面的代码蓝图可以看出,我在 demoMethod(它有一个同步块)和 helpMethod 中都有记录器。现在我遇到的问题是
Unguarded read missing_lock:在没有持有锁 TempClassName.tmpObj 的情况下访问记录器在其他地方,记录器在 12 次中有 8 次被持有 TempClassName.tmpObj 访问。
我不太确定是什么导致了这个问题,因为我使用的记录器是线程安全的。任何人都可以就可能导致此问题的原因提供更多见解。
解决方法
此报告的主要原因是:“在其他地方,12 次中有 8 次使用 TempClassName.tmpObject 访问记录器。”也就是说,在源代码中的 12 个文本位置访问(读取或写入,但不包括初始化)成员 logger
,并且对于其中的 8 个位置,已知 tmpObject
锁由正在执行的线程。因此,该工具得出结论,程序员的意图是 tmpObject
必须持有才能访问 logger
。显然,12 个中有 8 个高于将关联视为不仅仅是巧合的可配置阈值。因此,该工具会将与模式的偏差报告为可能的错误。我天真地希望 logger
总共有 4 个报告,您引用的就是其中一个(尽管可能会因存在不同的可能调用路径而变得复杂)。
这可能是误报。这个检查器对同步问题没有深入的理解,它只是从它在代码中发现的模式推断出来。如果,如您所说,Logger
类是线程安全的,并且 logger
成员本身没有读/写或写/写危险,那么它应该可以安全地将此报告视为虚假消息。
此外,请注意,在您提供的代码片段中,helperMethod
是 private
,仅被调用一次,并且该调用站点本身位于 synchronized
块内。如果真实代码没有任何其他调用点,那么这可能只是 Coverity 工具中的一个错误,因为 helperMethod
中的访问总是在持有锁时发生,并且该工具应该意识到这一点事实。
但还有一个问题:你引用的消息引用了tmpObject
,而你发布的代码引用了tmpObj
,它们是不同的名称。这只是您帖子中的一个错字,还是真正的代码实际上有两个不同的“临时对象”在四处乱跑造成混乱?如果是这样,那可能才是真正的问题。
撇开这份报告的细节不谈,请注意 Java 并发性比起初看起来要困难得多和微妙得多。如果您不精通该主题(首先,您是否对“之前发生过”有深入了解?),请在驳回报告之前咨询正在研究或进行一些额外研究的人。这个检查器的理解可能很肤浅,但根据我的经验,在它标记的任何代码中仔细检查并发的使用通常是值得的。
披露:我之前受雇于 Synopsys/Coverity,并帮助构建 Coverity 工具。