Я должен всегда делать свой код Java ориентированным на многопотоковое исполнение, или по производительности причинам делают это только при необходимости?

Другое событие 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));
}

26
задан Alex Miller 8 August 2011 в 19:24
поделиться

11 ответов

Начнем с данных. Решите, какие данные передаются явно, и защитите их. Если это вообще возможно, инкапсулируйте блокировку с данными. Используйте существующие параллельные многопоточные коллекции.

По возможности используйте неизменяемые предметы. Сделайте атрибуты окончательными, установите их значения в конструкторах. Если вам нужно «изменить» данные, рассмотрите возможность возврата нового экземпляра. Неизменяемые объекты не нуждаются в блокировке.

Для объектов, которые не являются общими или ограниченными потоками, не тратьте время на то, чтобы сделать их потокобезопасными.

Документировать ожидания в коде. Аннотации JCIP являются лучшим предопределенным выбором.

21
ответ дан Alex Miller 28 November 2019 в 06:35
поделиться

Чтобы избежать условий гонки, заблокируйте только один объект - утомительно прочитайте описания условий гонки, и вы обнаружите, что перекрестные блокировки (условие гонки ошибочно - гонка останавливается там) всегда являются следствием попытки двух + потоков заблокировать два + объекта.

Сделайте все методы синхронизированными и проведите тестирование - для любого реального приложения, которое фактически имеет дело с проблемами синхронизации, это небольшая стоимость. Они не говорят вам, что все это блокирует 16-битные таблицы указателей ... в этот момент вы ...

Просто следите за тем, чтобы ваше резюме с гамбургерами было актуальным.

0
ответ дан Nicholas Jordan 28 November 2019 в 06:35
поделиться

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

0
ответ дан dacracot 28 November 2019 в 06:35
поделиться

Разрабатывайте отдельно классы для использования из нескольких потоков и документируйте другие для использования только из одного потока.

С однопоточными гораздо проще работать.

Разделение многопоточной логики помогает сделать синхронизацию правильной.

0
ответ дан iny 28 November 2019 в 06:35
поделиться

Если вы хотите следить за тем, что Sun делала в Java API, вы можете взглянуть на классы коллекций. Многие распространенные классы коллекций не являются поточно-ориентированными, но имеют поточно-ориентированные аналоги. По словам Джона Скита (см. Комментарии), многие из классов Java изначально были поточно-ориентированными, но не приносили пользы разработчикам, поэтому некоторые классы теперь имеют две версии: одна - поточно-безопасная, а другая - не поточно-безопасная.

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

0
ответ дан Thomas Owens 28 November 2019 в 06:35
поделиться

Я нашел JCIP аннотации очень полезный объявлять, какие классы ориентированы на многопотоковое исполнение. Моя команда аннотирует наши классы как @ThreadSafe, @NotThreadSafe или @Immutable. Это намного более ясно, чем необходимость считать Javadoc, и , FindBugs помогает нам найти нарушения @Immutable и , @GuardedBy сокращается также.

2
ответ дан Chris Dolan 28 November 2019 в 06:35
поделиться

Так же, как дополнительное замечание: Синхронизация! = Потоковая безопасность. Тем не менее, вы не можете одновременно изменять данные, но вы можете читать их одновременно. Поэтому следует помнить о модели памяти Java, где синхронизация означает обеспечение надежности данных, доступных во всех потоках, а не только защиту их одновременной модификации.

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

3
ответ дан ReneS 28 November 2019 в 06:35
поделиться

Я лично только разработал бы классы, которые "ориентированы на многопотоковое исполнение" при необходимости - на принципе, оптимизируют только при необходимости. Sun, кажется, пошел тем же путем с примером единственных потоковых классов наборов.

Однако существуют некоторые хорошие принципы, которые помогут Вам так или иначе, если Вы решите измениться:

  1. самый важный: ДУМАЙТЕ ПЕРЕД СИНХРОНИЗАЦИЕЙ. У меня был коллега однажды, который раньше синхронизировался, материал "на всякий случай - в конце концов, синхронизировался, должно быть лучше, правильно?" Это НЕПРАВИЛЬНО, и было причиной нескольких ошибок мертвой блокировки.
  2. , Если Ваши Объекты могут быть неизменными, сделайте их неизменными. Это не только поможет с поточной обработкой, поможет им безопасно использоваться в наборах, поскольку ключи для Карт и т.д.
  3. Сохраняют Ваши Объекты максимально простыми. Каждый должен идеально только сделать одно задание. Если Вы когда-нибудь находите, что могли бы хотеть синхронизировать доступ к половине участников, то возможно необходимо разделить Объект в два.
  4. Изучают java.util.concurrent и используют его, когда это возможно. Их код будет лучше, быстрее и более безопасным, чем Ваш (или мой) в 99% случаев.
  5. Read Параллельное Программирование в Java, это является большим!
4
ответ дан Nick Fortescue 28 November 2019 в 06:35
поделиться

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

Если явно не указано, что объект является потокобезопасным, ожидается, что это не так.

6
ответ дан dpurrington 28 November 2019 в 06:35
поделиться

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

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

Однако я делаю также (где соответствующий), создают неизменные типы, которые естественно поддаются многопоточности - а также быть легче рассуждать о в целом.

27
ответ дан Jon Skeet 28 November 2019 в 06:35
поделиться

Вы должны точно знать, какие сегменты вашего кода будут многопоточными, а какие нет.

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

Остальные не делают и, следовательно, сделать его потокобезопасным было бы тратой.

Например, с помощью графического пользовательского интерфейса Sun просто решила, что ни один из них не будет многопоточным.

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

Изначально Sun выпустила поточно-безопасные коллекции (только). проблема в том, что потокобезопасность не может быть сделана не-потокобезопасной (в целях производительности). Так что теперь они выпустили версии без использования потоков с оболочками, чтобы сделать их безопасными. В большинстве случаев обертки не нужны - предположим, что если вы сами не создаете потоки, то ваш класс не обязательно должен быть безопасным для потоков - но ДОКУМЕНТИТЕ его в javadocs.

1
ответ дан Bill K 28 November 2019 в 06:35
поделиться