我有一个我需要使用的库,它有一个静态值的危险初始化(这个类已经被剥离到示例的最小值):
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
可能会有危险,因为其他人可能会改变价值,但......
我实际上是在做一些危险的事情(而且只是看不到它)?有一个更好的方法吗?
不幸的是,使用不同的TheirBaseClass
不是一种选择。
相关
答案 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.
}
时才会发生。