RFR 8017540: Improve multi-threaded contention behavior of BigInteger.toString() radix conversion cache

Dmitry Nadezhin dmitry.nadezhin at gmail.com
Wed Jun 26 03:31:52 UTC 2013


We have two versions after private discussion with Aleksey.

BigInteger getRadixConversionCache(int radix, int exponent) {
  BigInteger[][] pc = powerCache; // volatile read
  BigInteger[] cacheLine = pc[radix];
  if (exponent < cacheLine.length)
      return cacheLine[exponent];

  int oldSize = cacheLine.length;
  cacheLine = Arrays.copyOf(cacheLine, exponent + 1);
  for (int i = oldSize; i < exponent + 1; i++)
      cacheLine[i] = cacheLine[i - 1].square();

  pc = Arrays.copyOf(powerCache);
  pc[radix] = cacheLine;
  powerCache = pc; // volatile write, publish
  return cacheLine[exponent];
}

BigInteger getRadixConversionCache(int radix, int exponent) {
  BigInteger[][] pc = powerCache; // volatile read
  BigInteger[] cacheLine = pc[radix];
  if (exponent < cacheLine.length)
      return cacheLine[exponent];

  int oldSize = cacheLine.length;
  cacheLine = Arrays.copyOf(cacheLine, exponent + 1);
  for (int i = oldSize; i < exponent + 1; i++)
       cacheLine[i] = cacheLine[i - 1].square();

  synchronized (BigInteger.class) {
    if (powerCache[radix].length < cacheLine.length) {
      pc = Arrays.copyOf(powerCache);
      pc[radix] = cacheLine;
      powerCache = pc; // volatile write, publish
    }
  }
  return powerCache[radix][exponent];
}

The first version is simpler but sometimes a thread may discard powers with
larger exponents computed by another thread.
A thread may discard only powers computed by itself In the second version.


On Tue, Jun 25, 2013 at 11:53 PM, Aleksey Shipilev <
aleksey.shipilev at oracle.com> wrote:

> On 06/25/2013 11:36 PM, Dmitry Nadezhin wrote:
> > What about such code ?
> >
> > BigInteger getRadixConversionCache(int radix, int exponent) {
> >   BigInteger retVal = null;
> >   BigInteger[][] pc = powerCache; // volatile read
> >   BigInteger[] cacheLine = pc[radix];
> >   int oldSize = cacheLine.length;
> >   if (exponent >= oldSize) {
> >       cacheLine = Arrays.copyOf(cacheLine, exponent + 1);
> >       for (int i = oldSize; i <= exponent; i++) {
> >           retVal = cacheLine[i - 1].square();
> >           cacheLine[i] = retVal;
> >       }
> >       synchronized (pc) {
> >         if (pc[radix].length < cacheLine.length) {
> >           pc[radix] = cacheLine;
> >           powerCache = pc; // volatile write, publish
> >         }
> >       }
> >   } else {
> >       retVal = cacheLine[exponent];
> >   }
> >   return retVal;
> > }
>
> Still the same race. The reader thread sees the full-length cacheLine
> early, but the elements are not yet there.
>
> > Is dummy volatile write necessary inside synchronized block ?
> >           powerCache = pc; // volatile write, publish
> >
>
> Yes, since you need to have the matched synchronized(pc) otherwise to
> produce the pairwise "acquire".
>
> -Aleksey.
>
>



More information about the core-libs-dev mailing list