Как синхронизировать один элемент целочисленного массива?

#java #arrays #synchronized

#java #массивы #синхронизировано

Вопрос:

Если я хочу заблокировать весь массив, я могу использовать synchronized ключевое слово следующим образом:

 int arr[];

synchronized void inc(int a, int b){
    arr[a]=arr[a] b;
}
  

Но могу ли я заблокировать только элемент arr[a] , чтобы другие потоки могли одновременно читать / записывать другие элементы массива?

Ответ №1:

Может быть, более подходящая структура для вас AtomicIntegerArray

Комментарии:

1. Это, вероятно, лучший ответ, однако ответ Рэя — это решение, которое я искал для своего конкретного случая

Ответ №2:

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

 final Object[] locks = new Object[arr.length]:
for(int i = 0; i < arr.length; i  ) {
 locks[i] = new Object();
}
  

При блокировке: выполните

 synchronized(locks[a]) {
  // do something here
}
  

Ответ №3:

Нет, элементы массива являются примитивами, и вы не можете их заблокировать. (Это также не помогло бы, если бы они были объектами, потому что блокировка помогает только для изменяемых объектов. Вы хотите заблокировать индекс массива, а не содержимое по этому индексу).

Единственная возможная конструкция, которая приходит на ум, — это создать ключ, который однозначно ссылается на индекс массива, и синхронизировать его (или использовать a Semaphore ), но это поможет только в том случае, если другой поток обращается к массиву таким же образом.

Я бы сказал, что хорошей отправной точкой было бы изменить ваш дизайн, избавиться от массива int и использовать структуру данных, которая позволяет синхронизировать доступ к его элементам ( List завернутый с Collections.synchronizedList() ).

Ответ №4:

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

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

У вас может быть один синхронизированный массив счетчиков с очень дорогой блокировкой при каждом обновлении. (Синхронизация выполняется быстро, но намного, намного медленнее, чем добавление)

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