#java #concurrency #atomic-values
#java #параллелизм #атомарные значения
Вопрос:
Мне нужен AtomicByteArray для критически важного для памяти приложения, созданного по образцу AtomicIntegerArray Java. Моя реализация преобразует четыре байта в целое число и использует AtomicIntegerArray.
get()
Реализация тривиальна, а set()
реализации and довольно просты. Чем compareAndSwap()
сложнее. Моя реализация приведена ниже (она отлично работает в однопоточном режиме).
Я пытаюсь определить состояние гонки. Один из возможных сценариев заключается в том, что значения изменяются и меняются местами между вызовами get()
и compareAndSet()
, но это кажется безвредным.
Я пропустил что-нибудь, что может пойти не так?
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public boolean compareAndSet(final int i, final byte expected, final byte val) {
int idx = i >>> 2;
int shift = (i amp; 3) << 3;
while (true) {
final int num = this.array.get(idx);
// Check that the read byte is what we expected
if ((byte)(num >> shift) != expected) {
return false;
}
// If we complete successfully, all is good
final int num2 = (num amp; ~(0xff << shift)) | ((val amp; 0xff) << shift);
if ((num == num2) || this.array.compareAndSet(idx, num, num2)) {
return true;
}
}
}
Обновление: я внедрил базовую версию AtomicByteArray, которая объединяет улучшения в приведенном ниже ответе.
Комментарии:
1. Я бы
i / 4
->i >>> 2
и8 * (i % 4)
->(i amp; 3) << 3
2. Относится ли это к проверке кода ?
3. @PeterLawrey Спасибо за предложение. Исправлено.
4. @JimGarrison Я не знаю, но я рад сделать репост там. Это скорее вопрос параллелизма, чем вопрос кода Java.
5. Именно поэтому я попросил вместо голосования закрыть тему. Мне любопытно, к чему относится этот вопрос.
Ответ №1:
Вы могли бы рассмотреть возможность использования маски. Это может быть быстрее / чище.
int idx = i >>> 2;
int shift = (i amp; 3) << 3;
int mask = 0xFF << shift;
int expected2 = (expected amp; 0xff) << shift;
int val2 = (val amp; 0xff) << shift;
while (true) {
final int num = this.array.get(idx);
// Check that the read byte is what we expected
if ((num amp; mask) != expected2) return false;
// If we complete successfully, all is good
final int num2 = (num amp; ~mask) | val2;
if ((num == num2) || this.array.compareAndSet(idx, num, num2)) {
return true;
}
}
Вы хотите выполнить минимум работы внутри цикла, чтобы в случае возникновения разногласий вы могли повторить попытку как можно быстрее.
Я не уверен num == num2
, что это помогает больше, чем вредит. Я предлагаю вам попробовать это без сравнения.
Комментарии:
1. Спасибо! Я предложил несколько исправлений, связанных с подписью и байтом в int для продвижения. Чтобы быть точным, когда вы выполняете побитовые операции над -1 (0xff), он сначала повышается до int -1 (0xfffffff).
2. Я реализовал базовую версию, которая объединяет ваши предложения в github.com/shilad/wikibrain/blob/master/wikibrain-utils/src /…