int first_value = Integer.parseInt(cards[index]);
при написании вышеуказанного утверждения вы пытаетесь разобрать «Туз клубов» как число.
вы можете использовать следующий метод, чтобы проверить, может ли какая-либо строка быть проанализирована как Integer:
boolean tryParseInt(String value) { try { Integer.parseInt(value); return true; } catch (NumberFormatException e) { return false; } }
Что касается вашего вопроса, то что такое NumberFormatException: указывается, что приложение попытался преобразовать строку в один из числовых типов, но строка не имеет соответствующего формата. (ref - http://docs.oracle.com/javase/7/docs/api/java/lang/NumberFormatException.html )
Ну, нет никакой двойной проверки блокировки для производительности. Это паттерна .
Оставляя эмоции в стороне, volatile
здесь, потому что без него к тому времени, когда второй поток проходит instance == null
, первая нить не может построить new Singleton()
все же: никто не обещает, что создание объекта происходит до присваивания instance
для любого потока, кроме фактически создающего объект.
volatile
в свою очередь устанавливает происходит до отношения между чтением и записью и исправляет разбитый шаблон.
Если вы ищете производительность, используйте вместо этого внутренний статический класс.
Если у вас его нет, второй поток может попасть в синхронизированный блок после первого установленного значения null, а ваш локальный кеш все равно будет считать, что он равен нулю.
Первый не для правильности (если бы вы были правы, что это было бы самозавершением), а скорее для оптимизации.
Объявление переменной как volatile
гарантирует, что все обращения к ней фактически считывают текущее значение из памяти.
Без volatile
компилятор может оптимизировать доступ к памяти и сохранить ее значение в регистр, поэтому только первое использование переменной считывает фактическую ячейку памяти, содержащую переменную. Это проблема, если переменная изменена другим потоком между первым и вторым доступом; первый поток имеет только копию первого (предварительно измененного) значения, поэтому второй оператор if
проверяет устаревшую копию значения переменной.
volatile
. Регистры не имеют ничего общего с неполными объектами и проблемой DCL.
– alf
21 October 2011 в 23:14
volatile
слишком узкое - если все это было волатильно, двойная проверенная блокировка отлично работала бы в & lt; Java5. volatile
вводит барьер памяти, делающий определенное переупорядочение незаконным - без этого, даже если мы никогда не будем читать устаревшие значения из памяти, он все равно будет небезопасным. Редактировать: alf избил меня до этого, не должен был получить хороший чай;)
– Voo
21 October 2011 в 23:18
volatlie
к singleton делает ваш поток повторно -read main memory - но это вторичный эффект, а не причина проблемы :))
– alf
21 October 2011 в 23:18
Неустойчивое чтение не очень дорого само по себе.
Вы можете создать тест для вызова getInstance()
в узком цикле, чтобы наблюдать влияние изменчивого чтения; однако этот тест нереалистичен; в такой ситуации программист обычно вызывал getInstance()
один раз и кэшировал экземпляр для продолжительности использования.
Другой impl с помощью поля final
(см. wikipedia). Для этого требуется дополнительное чтение, которое может стать дороже, чем версия volatile
. Версия final
может быть быстрее в узком цикле, однако этот тест является спорным, как ранее утверждалось.
Как цитируется @irreputable, volatile не дорогая. Даже если это дорого, согласованность должна быть отдана приоритету над производительностью.
Есть еще один чистый элегантный способ для Lazy Singletons.
public final class Singleton {
private Singleton() {}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
Исходная статья: Инициализация-по-запросу_holder_idiom из википедии
< blockquote>В программной инженерии идиома Инициализация по требованию (шаблон дизайна) - это ленивый загруженный синглтон. Во всех версиях Java идиома обеспечивает безопасную, очень параллельную ленивую инициализацию с хорошей производительностью
. Поскольку у класса нет инициализируемых переменных static
, инициализация завершается тривиально.
Определение статического класса LazyHolder
внутри него не инициализируется до тех пор, пока JVM не определит, что LazyHolder должен быть выполнен.
Статический класс LazyHolder
выполняется только тогда, когда статический метод getInstance
вызывается в классе Singleton, и в первый раз это произойдет, JVM будет загружать и инициализировать класс LazyHolder
.
Это решение является потокобезопасным, не требуя специальных языковых конструкций (т.е. volatile
или synchronized
).
volatile
медленнее обычного. Если вы ищете производительность, пойдите для шаблона класса владельца.volatile
здесь просто для того, чтобы показать, что существует способ i>, чтобы заставить сломанный шаблон работать. Это скорее проблема кодирования, чем настоящая проблема. – alf 21 October 2011 в 23:43Foo.getInstance()
- просто выражение, чтобы каким-то образом получить Foo, оно ничем не отличается от@Inject Foo foo
; в любом случае сайт, который запрашивает Foo, является агностиком, из которого возвращается Foo, и каким образом статические и временные зависимости одинаковы. – irreputable 22 October 2011 в 04:18static
factory
- это соблазн называть его глубоко внутри кода, который не должен знать о методеgetInstance()
и вместо этого требовать предоставления экземпляра. – Tim Bender 8 June 2013 в 03:05