Я пытаюсь использовать блокировку с двойным проверкой для поддержки массива биномиальных коэффициентов, но недавно я прочитал, что блокировка с двойной проверкой не работает. Эффективность чрезвычайно важна, поэтому использование volatile не является вариантом, если только внутри условных операторов. Я не вижу способа использовать статический класс с одноэлементным объектом (это часть структуры, и я не знаю, какие числа людей должны будут использовать эту функцию, поэтому я не могу догадаться, что такое максимум выбранное значение будет или будет ли функция вообще использоваться). Единственное, о чем я могу думать, это сделать все, что не статично, и настаивать на том, чтобы каждый поток, который должен использовать этот метод, создавал экземпляр объекта Select со своим собственным массивом. Похоже, это не обязательно.Двойная проверка блокировки для растущего массива биномиальных коэффициентов
public static final class Util{
/**
* Static array of nCr values
*/
public static long[][] nCr_arr;
/**
* Calculate binomial coefficient (n k)
*
* @param n
* n
* @param k
* k
* @return n choose k
*/
public static long nCr(int n, int k) {
if (k < 0)
throw new ArithmeticException("Cannot choose a negative number");
if (n < 0) {
if (k % 2 == 0)
return nCr(-n + k - 1, k);
else
return -nCr(-n + k - 1, k);
}
if (k > n)
return 0;
if (k > n/2)
k = n - k;
if (nCr_arr == null) {
synchronized (Util.class) {
if (nCr_arr == null)
nCr_arr = new long[n + 1][];
}
}
if (nCr_arr.length <= n) {
synchronized (Util.class) {
if (nCr_arr.length <= n) {
long[][] newNCR = new long[n + 1][];
System.arraycopy(nCr_arr, 0, newNCR, 0, nCr_arr.length);
nCr_arr = newNCR;
}
}
}
if (nCr_arr[n] == null) {
synchronized (Util.class) {
if (nCr_arr[n] == null)
nCr_arr[n] = new long[k + 1];
}
}
if (nCr_arr[n].length <= k) {
synchronized (Util.class) {
if (nCr_arr[n].length <= k) {
long[] newNCR = new long[k + 1];
System.arraycopy(nCr_arr[n], 0, newNCR, 0,
nCr_arr[n].length);
nCr_arr[n] = newNCR;
}
}
}
if (nCr_arr[n][k] == 0) {
if (k == 0)
nCr_arr[n][k] = 1;
else
nCr_arr[n][k] = nCr(n, k - 1) * (n - (k - 1))/k;
}
return nCr_arr[n][k];
}
}
Я бы рекомендовал сделать это настоящим классом. Что произойдет, если кто-то вызовет ваш метод во второй раз с более крупным «n»? Массив будет инициализирован, но не будет достаточно большим. Не только это, если есть потоки, которые используют этот статический метод одновременно, у вас будут серьезные проблемы. –
Кроме того, если вы не ожидаете одновременного использования, устраните этот синхронизированный блок, поскольку это уже не имеет значения, а затем тщательно документируйте это. Вам не нужно беспокоиться о блокировке вообще, если вы просто используете это в одном потоке. Но, как мой комментарий выше, если вы используете это с несколькими потоками, у вас много других проблем. –
Простите, что вы пытаетесь расширить массив в следующем тесте. Здесь все еще есть проблемы параллелизма с последующими назначениями. –