System.console()中可能存在JDK错误

时间:2015-05-08 07:14:05

标签: java

以下代码来自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;
 }

我是对的吗?您的意见是什么?

2 个答案:

答案 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个对象。