java关于单例多线程的一些东西
我使用单例读取配置:
Class Property {
private String username;
private String password;
private static Property props;
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public static Property getInstance() {
if(props == null) {
synchronized(Property.class) {
props = new Property();
props.initial();
}
}
return props;
}
public void initial() {
Properties prop = new Properties();
prop.load(new FileInputStream(new File("application.properties")));
username = prop.getProperty("username");
password = prop.getProperty("password");
}
}
然后,在第一个线程中,我得到了属性的一个实例,如props = Property.getInstance
我这样调用方法getUsername()
和getPassword()
:
props.getUsername()
/props.getPassword()
但是,这两个方法返回null。在第二个线程和之后的线程中,我可以从这两个方法中获取用户名和密码
我不知道为什么会这样。有人能帮我吗
# 1 楼答案
我想这是道具。上面代码中的getProperty在发布问题时是一个输入错误
在synchronized语句之前,检查props==null。可能已经创建了props(新属性),所以不是null,但是对initial的调用还没有完成。因此,在调用getUsername/password之前,getInstance返回的对象尚未正确初始化。最简单的解决方案是使整个方法同步,但这可能是一个性能问题
另外,在当前的实现中,您可能会创建两个单例实例。例如,如果props==null,并且最终两个线程都进入同步块。您还应该检查synchronized部分中的props是否为null,以避免创建两个实例(请参阅:http://en.wikipedia.org/wiki/Double-checked_locking)
处理多线程单例的更优雅的方法可能是按需初始化习惯用法(http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom)
# 2 楼答案
执行新的
Property()
后,“Props”不再为空。因此,即使未完全执行initial()
-方法,也可能返回props
请尝试以下代码:
# 3 楼答案
antonis_wrx和Andy N.都说您的同步不够“宽”:
设想两个线程并行执行。线程A执行第1行,并且
props == null
返回true。紧接着,操作系统切换到线程B。线程B也执行相同的第1行,检查仍然返回true(props仍然为null)。现在两个线程都将继续并执行同步块因此,假设线程A获取属性上的监视器。首先初始化(第2行)并初始化道具(第2-5行)。现在线程B可以自由地获取第2行中的监视器——它执行第3行,此时,线程C调用
getInstance().getUsername()
线程C的
getInstance
执行第1行,该行返回false,然后返回props
(这是线程B刚刚构造到new Property()
)。在这个未初始化的属性对象上调用getUsername()
会得到所看到的空值请注意,对于这个示例,线程C也可能是同一个线程A(我只是想让它更易于阅读)
您可以使用已经提出的方法(同步整个
getInstance
方法)来解决问题。另一种方法是使用静态块进行初始化,如下所示:# 4 楼答案
将静态
props
更改为prop
atinitial()
方法