Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Начнем с данных. Решите, какие данные передаются явно, и защитите их. Если это вообще возможно, инкапсулируйте блокировку с данными. Используйте существующие параллельные многопоточные коллекции.
По возможности используйте неизменяемые предметы. Сделайте атрибуты окончательными, установите их значения в конструкторах. Если вам нужно «изменить» данные, рассмотрите возможность возврата нового экземпляра. Неизменяемые объекты не нуждаются в блокировке.
Для объектов, которые не являются общими или ограниченными потоками, не тратьте время на то, чтобы сделать их потокобезопасными.
Документировать ожидания в коде. Аннотации JCIP являются лучшим предопределенным выбором.
Чтобы избежать условий гонки, заблокируйте только один объект - утомительно прочитайте описания условий гонки, и вы обнаружите, что перекрестные блокировки (условие гонки ошибочно - гонка останавливается там) всегда являются следствием попытки двух + потоков заблокировать два + объекта.
Сделайте все методы синхронизированными и проведите тестирование - для любого реального приложения, которое фактически имеет дело с проблемами синхронизации, это небольшая стоимость. Они не говорят вам, что все это блокирует 16-битные таблицы указателей ... в этот момент вы ...
Просто следите за тем, чтобы ваше резюме с гамбургерами было актуальным.
"Всегда" очень опасное слово в разработке программного обеспечения..., выбор как это "всегда" ситуативен.
Разрабатывайте отдельно классы для использования из нескольких потоков и документируйте другие для использования только из одного потока.
С однопоточными гораздо проще работать.
Разделение многопоточной логики помогает сделать синхронизацию правильной.
Если вы хотите следить за тем, что Sun делала в Java API, вы можете взглянуть на классы коллекций. Многие распространенные классы коллекций не являются поточно-ориентированными, но имеют поточно-ориентированные аналоги. По словам Джона Скита (см. Комментарии), многие из классов Java изначально были поточно-ориентированными, но не приносили пользы разработчикам, поэтому некоторые классы теперь имеют две версии: одна - поточно-безопасная, а другая - не поточно-безопасная.
Мой совет - не делать код потокобезопасным до тех пор, пока это не понадобится, так как с безопасностью потоков связаны некоторые накладные расходы. Я думаю, что это относится к той же категории, что и оптимизация - не делайте этого раньше, чем нужно.
Я нашел JCIP аннотации очень полезный объявлять, какие классы ориентированы на многопотоковое исполнение. Моя команда аннотирует наши классы как @ThreadSafe, @NotThreadSafe или @Immutable. Это намного более ясно, чем необходимость считать Javadoc, и , FindBugs помогает нам найти нарушения @Immutable и , @GuardedBy сокращается также.
Так же, как дополнительное замечание: Синхронизация! = Потоковая безопасность. Тем не менее, вы не можете одновременно изменять данные, но вы можете читать их одновременно. Поэтому следует помнить о модели памяти Java, где синхронизация означает обеспечение надежности данных, доступных во всех потоках, а не только защиту их одновременной модификации.
И да, по моему мнению, потокобезопасность должна быть встроена с самого начала, и это зависит от логики приложения, если вам нужна обработка параллелизма. Никогда не принимайте что-либо, и даже если ваш тест, кажется, в порядке, условия гонки - спящие собаки.
Я лично только разработал бы классы, которые "ориентированы на многопотоковое исполнение" при необходимости - на принципе, оптимизируют только при необходимости. Sun, кажется, пошел тем же путем с примером единственных потоковых классов наборов.
Однако существуют некоторые хорошие принципы, которые помогут Вам так или иначе, если Вы решите измениться:
Следуйте принципу «как можно проще, но не проще». При отсутствии требования вы не должны делать их потокобезопасными. Это будет спекулятивным и, вероятно, ненужным. Поточно-ориентированное программирование значительно усложняет ваши классы и, вероятно, сделает их менее производительными из-за задач синхронизации.
Если явно не указано, что объект является потокобезопасным, ожидается, что это не так.
Я раньше пытался сделать все ориентированным на многопотоковое исполнение - тогда я понял, что самое значение "ориентированных на многопотоковое исполнение" зависит от использования. Вы часто просто не можете предсказать, что использование и вызывающая сторона будут иметь для принятия мер так или иначе для использования его ориентированным на многопотоковое исполнение способом.
В эти дни я пишу почти все принимающее единственную поточную обработку и помещаю знание поточной обработки в выбор немного мест, где это имеет значение.
Однако я делаю также (где соответствующий), создают неизменные типы, которые естественно поддаются многопоточности - а также быть легче рассуждать о в целом.
Вы должны точно знать, какие сегменты вашего кода будут многопоточными, а какие нет.
Не имея возможности сконцентрировать область многопоточности в небольшой управляемой секции, у вас ничего не получится. Многопоточные части вашего приложения необходимо тщательно изучить, полностью проанализировать, понять и адаптировать для многопоточной среды.
Остальные не делают и, следовательно, сделать его потокобезопасным было бы тратой.
Например, с помощью графического пользовательского интерфейса Sun просто решила, что ни один из них не будет многопоточным.
О, и если кто-то использует ваши классы - он должен убедиться, что если он находится в многопоточном разделе, то сделать его поточным.
Изначально Sun выпустила поточно-безопасные коллекции (только). проблема в том, что потокобезопасность не может быть сделана не-потокобезопасной (в целях производительности). Так что теперь они выпустили версии без использования потоков с оболочками, чтобы сделать их безопасными. В большинстве случаев обертки не нужны - предположим, что если вы сами не создаете потоки, то ваш класс не обязательно должен быть безопасным для потоков - но ДОКУМЕНТИТЕ его в javadocs.