是FindBugs' JLM_JSR166_UTILCONCURRENT_MONITORENTER'在这种情况下可以安全地忽略

时间:2016-08-25 15:25:43

标签: java static initialization findbugs

我有一个我需要使用的库,它有一个静态值的危险初始化(这个类已经被剥离到示例的最小值):

public TheirBaseClass {
    public static String PathToUse = null;

    public BaseClass(){
        PathToUse = "Configured";

        // ... 
        // do some other stuff with other side effects 
        // ...
    }
}

我有一个案例,我尝试从值ConfigValue读取而不实例化类(以避免一些副作用)。

Paths.get(TheirBaseClass.PathToUse).toFile()....

这会导致NullPointerException

因为我需要使用这个类,所以我希望继承它,并尝试采取措施确保在访问静态时进行初始化。

public MyBaseClass extends TheirBaseClass{

    private static final AtomicBoolean isInitialized = new AtomicBoolean(false);

    static {
        MyBaseClass.Initialize();
    }

    public static void Initialize(){
        // FindBugs does not like me synchronizing on a concurrent object
        synchronized(isInitialized){
            if( isInitialized.get() ){
                return;
            }
            new TheirBaseClass();
            isInitialized.set(true);
        }
    }

    public MyBaseClass(){
        super();
    }

}

允许我

MyBaseClass.Initialize();
Paths.get(MyBaseClass.PathToUse).toFile()....

这似乎运作得相当好(并解决了我们一直有的其他一些幻影缺陷)。它允许TheirBaseClass自然地运行,同时允许我在我可能需要的几种情况下安全地强制初始化。

然而,当我针对此代码运行FindBugs时,我得到JLM_JSR166_UTILCONCURRENT_MONITORENTER。阅读说明后,我同意使用AtomicBoolean可能会有危险,因为其他人可能会改变价值,但......

  1. 我认为在这种情况下可以放心(但有疑问)
  2. 我通常更喜欢重写代码而不是放置忽略标记
  3. 我实际上是在做一些危险的事情(而且只是看不到它)?有一个更好的方法吗?

    不幸的是,使用不同的TheirBaseClass不是一种选择。

    相关

1 个答案:

答案 0 :(得分:1)

您可能会发现更容易调整lazy holder idiom

.icon {
    border: 1px solid black;
    display: inline-block;
    height: 25px;
    text-indent: -999em;
    vertical-align: middle;
    width: 25px;
}

    <a role="button" href="javascript:void(0);" aria-label="select product" aria-describedby="navigation">
        <span id="navigation" class="icon >Enter to open, tab to navigate</span>
    </a>

这使用了类加载仅发生一次并同步(在单个类加载器中)的事实。它仅在您实例化public MyBaseClass { private static class Initializer { static { new TheirBaseClass(); } // Doesn't actually do anything; merely provides an expression // to cause the Initializer class to be loaded. private static void ensureInitialized() {} } { Initializer.ensureInitialized(); } // Rest of the class. } 时才会发生。