以下代码来自java.lang.System.console()
方法:
private static volatile Console cons = null;
/**
* Returns the unique {@link java.io.Console Console} object associated
* with the current Java virtual machine, if any.
*
* @return The system console, if any, otherwise <tt>null</tt>.
*
* @since 1.6
*/
public static Console console() {
if (cons == null) {
synchronized (System.class) {
cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
}
}
return cons;
}
在我看来,这是这种方法的一个错误。 我们应该这样写:
public static Console console() {
if (cons == null) {
synchronized (System.class) {
if (cons == null)
cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
}
}
return cons;
}
我是对的吗?您的意见是什么?
答案 0 :(得分:4)
不是。您可以为其分配一个值,它已经初始化。我认为空检查是多余的,它已在外部检查,并在控制台的JavaIoAccess实现中作为Tagir Valeev suggested。
您可能正在考虑线程争用,并且因为初始化发生在同步块内部,同时访问它的多个线程将触发冗余重新初始化。
所以你可以说减少开销而不是错误可能会有所改善。
但是你应该在Double checked locking上阅读更多内容,它包含了你的场景。详情如下
<小时/> 看到在J2SE 1.4(及更早版本)中使用它与各种编译器的微妙问题很有意思。
在J2SE 5.0之后,这些问题已得到修复
volatile关键字现在确保多个线程处理 单身实例正确。
您会注意到Console静态对象是易失性的。
通过使用上述链接中描述的实现:
private static volatile Console cons = null;
public static Console console() {
Console result = console;
if (result == null) {
synchronized (System.class) {
result = console;
if (result == null) {
console = result =sun.misc.SharedSecrets.getJavaIOAccess().console();
}
}
}
return result;
}
您可以获得这样的性能提升:
注意局部变量结果,这似乎是不必要的。这确保了 在 控制台 已经初始化的情况下(即大多数情况下) 时间),volatile字段只被访问一次(由于&#34;返回 结果;&#34;而不是&#34;返回 控制台 ;&#34;),这可以改进方法&#34; 总体性能高达25% - 注意:为了清晰起见,用控制台替换了帮助
但我不确定第一次从多线程调用console()的次数 - 之后,由于outter null检查,初始化不再是问题。
此解决方案还会产生开销,因此实际的性能提升值得商榷。因此,您的建议(如上所述)最多可以被视为一种改进。
答案 1 :(得分:3)
如果您查看JavaIOAccess
的{{3}},您会发现其中有一个空检查:
public Console console() {
if (istty()) {
if (cons == null)
cons = new Console();
return cons;
}
return null;
}
由于此方法是初始化该变量的唯一方法,因此嵌套空检查驻留在另一个方法中不是问题。它仍然无法获得两个不同的Console
个对象。