Параллелизм Java - запись в разные индексы одного и того же массива - PullRequest
31 голосов
/ 24 января 2012

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

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

Ответы [ 4 ]

34 голосов
/ 24 января 2012

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

Глава "Потоки и блокировки" в Спецификации языка Java начинается с утверждения:

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

[...]

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

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

11 голосов
/ 24 января 2012

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

1 голос
/ 24 января 2012

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

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

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

0 голосов
/ 24 января 2012

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

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

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

И

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...