Подтвердить что ты не робот

Java concurrency - запись в разные индексы одного и того же массива

Предположим, у меня есть массив данных, можно ли 2 потока безопасно записывать в разные индексы одного и того же массива одновременно? Я беспокоюсь о скорости записи, и я хочу синхронизировать бит "get index to write at" и фактическую запись.

Я пишу код, который позволяет мне предположить, что 2 потока не получат один и тот же индекс.

4b9b3361

Ответ 1

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

Глава "Темы и блокировки" в Спецификации языка Java начинается с сообщения:

17.4.1 Общие переменные

[...]

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

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

Ответ 2

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

Ответ 3

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

Если у вас были счетные переменные, которые перемещались в виде массивов, написанных в разных местах, вы могли столкнуться с проблемами concurrency. Возможно, по мере того как ваш массив заполняется, вы можете попробовать две записи и записать их в одно и то же место. Если у вас потенциально был читатель массива, который мог бы прочитать то же место, которое написано слишком, вы будете иметь проблемы concurrency. Кроме того, запись не делает ничего, если вы никогда не планируете читать ее, поэтому я думаю, что у вас будут проблемы с concurrency, когда вы переходите к добавлению читателя (который должен будет заблокировать ваших авторов). Тогда возникает вопрос: не двигайтесь ли туда, где потоки пишут, что заставляет его писать данные? И если вы никогда не двигаете головой, где пишет поток, почему вы используете массив? Просто дайте им отдельные задвижки или их собственные переменные, и они действительно разделяют их.

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

Ответ 4

Посмотрите CopyOnWriteArrayList, если вы в порядке с arrayList. из его документации,

Нитевидный вариант ArrayList, в котором все мутативные операции     (добавление, набор и т.д.) реализуются путем создания новой копии     базовый массив.

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

И

Экземпляр CopyOnWriteArrayList ведет себя как реализация List,     позволяет несколько одновременных чтений, а для чтения - одновременно с     написать. То, как это делается, состоит в том, чтобы каждый раз создавать новую копию списка     он изменяется.

Чтения не блокируют и эффективно оплачивают только стоимость изменчивого чтения;     Записи не блокируют чтение (или наоборот), но сразу может появиться только одна запись.