src/share/classes/java/math/BigInteger.java
Print this page
rev 7571 : 8017540: Improve multi-threaded contention behavior of radix conversion cache
Summary: Replace array of ArrayList of BigIntegers with a volatile two-dimensional BigInteger array eliminate the synchronization of getRadixConversionCache()
Reviewed-by: plevart, shade, bpb, alanb
Contributed-by: Peter Levart <peter.levart@gmail.com>, Dmitry Nadezhin <dmitry.nadezhin@oracle.com>, Aleksey Shipilev <aleksey.shipilev@oracle.com>
*** 1040,1050 ****
/**
* The cache of powers of each radix. This allows us to not have to
* recalculate powers of radix^(2^n) more than once. This speeds
* Schoenhage recursive base conversion significantly.
*/
! private static ArrayList<BigInteger>[] powerCache;
/** The cache of logarithms of radices for base conversion. */
private static final double[] logCache;
/** The natural log of 2. This is used in computing cache indices. */
--- 1040,1050 ----
/**
* The cache of powers of each radix. This allows us to not have to
* recalculate powers of radix^(2^n) more than once. This speeds
* Schoenhage recursive base conversion significantly.
*/
! private static volatile BigInteger[][] powerCache;
/** The cache of logarithms of radices for base conversion. */
private static final double[] logCache;
/** The natural log of 2. This is used in computing cache indices. */
*** 1061,1078 ****
/*
* Initialize the cache of radix^(2^x) values used for base conversion
* with just the very first value. Additional values will be created
* on demand.
*/
! powerCache = (ArrayList<BigInteger>[])
! new ArrayList[Character.MAX_RADIX+1];
logCache = new double[Character.MAX_RADIX+1];
for (int i=Character.MIN_RADIX; i<=Character.MAX_RADIX; i++)
{
! powerCache[i] = new ArrayList<BigInteger>(1);
! powerCache[i].add(BigInteger.valueOf(i));
logCache[i] = Math.log(i);
}
}
/**
--- 1061,1076 ----
/*
* Initialize the cache of radix^(2^x) values used for base conversion
* with just the very first value. Additional values will be created
* on demand.
*/
! powerCache = new BigInteger[Character.MAX_RADIX+1][];
logCache = new double[Character.MAX_RADIX+1];
for (int i=Character.MIN_RADIX; i<=Character.MAX_RADIX; i++)
{
! powerCache[i] = new BigInteger[] { BigInteger.valueOf(i) };
logCache[i] = Math.log(i);
}
}
/**
*** 3452,3477 ****
* If this value doesn't already exist in the cache, it is added.
* <p/>
* This could be changed to a more complicated caching method using
* <code>Future</code>.
*/
! private static synchronized BigInteger getRadixConversionCache(int radix,
! int exponent) {
! BigInteger retVal = null;
! ArrayList<BigInteger> cacheLine = powerCache[radix];
! int oldSize = cacheLine.size();
! if (exponent >= oldSize) {
! cacheLine.ensureCapacity(exponent+1);
! for (int i=oldSize; i<=exponent; i++) {
! retVal = cacheLine.get(i-1).square();
! cacheLine.add(i, retVal);
}
}
- else
- retVal = cacheLine.get(exponent);
! return retVal;
}
/* zero[i] is a string of i consecutive zeros. */
private static String zeros[] = new String[64];
static {
--- 3450,3478 ----
* If this value doesn't already exist in the cache, it is added.
* <p/>
* This could be changed to a more complicated caching method using
* <code>Future</code>.
*/
! private static BigInteger getRadixConversionCache(int radix, int exponent) {
! BigInteger[] cacheLine = powerCache[radix]; // volatile read
! if (exponent < cacheLine.length) {
! return cacheLine[exponent];
}
+
+ int oldLength = cacheLine.length;
+ cacheLine = Arrays.copyOf(cacheLine, exponent + 1);
+ for (int i = oldLength; i <= exponent; i++) {
+ cacheLine[i] = cacheLine[i - 1].pow(2);
}
! BigInteger[][] pc = powerCache; // volatile read again
! if (exponent >= pc[radix].length) {
! pc = pc.clone();
! pc[radix] = cacheLine;
! powerCache = pc; // volatile write, publish
! }
! return cacheLine[exponent];
}
/* zero[i] is a string of i consecutive zeros. */
private static String zeros[] = new String[64];
static {