2015-05-08 2 views
5

Следующий код пришел из java.lang.System.console() метода:Возможная ошибка в JDK 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; 
} 

Я прав? Каково ваше мнение?

ответ

3

Если посмотреть в implementation из JavaIOAccess, вы обнаружите, что есть нуль-проверка внутри него:

public Console console() { 
    if (istty()) { 
     if (cons == null) 
      cons = new Console(); 
      return cons; 
     } 
    return null; 
} 

Поскольку этот метод является единственным способом инициализировать эту переменную, то это не проблема, вложенная нулевая проверка находится в другом методе. До сих пор невозможно получить два разных объекта: Console.

+0

JavaIoAccess - это только интерфейс. Реализации консоли() могут отличаться. –

+1

Это не так. Это внутренний JDK-код и внутренний интерфейс JDK. В JDK существует только одна реализация. Если вы попытаетесь заменить его своей собственной реализацией, то вы используете Java не документально, поэтому ничего не будет гарантировано. В любом случае вы не сможете создать новый объект 'Console', поскольку класс' Console' является окончательным и имеет только частный конструктор. Конечно, вы можете играть с размышлением, чтобы получить доступ к частному конструктору или использовать другие способы стрелять в вашу ногу, но заявив, что что-то невозможное, я имею в виду «невозможно, если вы используете Java документированным способом». –

+0

Я вижу. Отметил! Я предположил, что это может измениться в зависимости от версии java. Но это выходит за рамки этой области. –

4

Это не так. Вы можете присвоить ему значение, и оно уже было инициализировано. Я думаю, что нулевая проверка избыточна, она уже проверяется снаружи и как Tagir Valeev suggested, внутри реализации консоли JavaIoAccess.

Возможно, вы думаете о конфликте потоков, и поскольку инициализация происходит внутри блока синхронизации, несколько потоков, обращающихся к нему в одно и то же время, вызывают избыточную повторную инициализацию.

Таким образом, вы можете сказать, что это может быть скорее улучшением для уменьшения накладных расходов, чем ошибки.

Однако вы должны узнать больше о Double checked locking, он содержит именно ваш сценарий. Подробности ниже


Интересно видеть тонкие проблемы использования его в J2SE 1.4 (и более ранних версиях) с различными компиляторами.

После J2SE 5.0 те проблемы были исправлены

Летучие ключевое слово в настоящее время гарантирует, что несколько потоков обработки одноэлементный экземпляр правильно.

Как вы заметили, статический объект 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; 
} 

Вы могли бы получить такой прирост производительности:

Примечание локальная переменная результата, который кажется ненужным. Это гарантирует , что в тех случаях, когда консоль уже инициализирована (т.е. большой части времени), летучее поле только доступ один раз (из-за «возвращением результата;» вместо «вернуть консоли ; "), который может улучшить общую производительность метода, на целых 25 процентов - примечания: заменить помощником с консолью для ясности

Но я не уверен, как часто утешают() вызываются из Многолучевых потоки первые время - после этого инициализация больше не является проблемой из-за проверки нулевого результата.

Это решение также создает накладные расходы, поэтому фактическое усиление производительности является спорным. Таким образом, ваше предложение (как принято выше) можно рассматривать в лучшем случае как улучшение.

+1

Большое вам спасибо за ваш ответ. – yuanfang

+1

Я очень рад, что я изучил умение, используя результат локальной переменной, чтобы улучшить производительность метода. Еще раз спасибо. – yuanfang

Смежные вопросы