Re: JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-26 Thread Aleksey Shipilev
On 08/22/2013 03:37 AM, Brian Burkhalter wrote:
 With respect to this issue
 
 http://bugs.sun.com/view_bug.do?bug_id=6470700
 
 the code of concern from java.lang.Math is
 
 701private static Random randomNumberGenerator;
 702
 703private static synchronized Random initRNG() {
 704Random rnd = randomNumberGenerator;
 705return (rnd == null) ? (randomNumberGenerator = new Random()) : 
 rnd;
 706 }
 
 731public static double random() {
 732Random rnd = randomNumberGenerator;
 733if (rnd == null) rnd = initRNG();
 734return rnd.nextDouble();
 735}
 
 where the class variable randomNumberGenerator is not used anywhere else in 
 the class. The complaint is that this is an instance of the broken 
 double-checked locking pattern. While at first glance this might appear to be 
 the case, it does not seem so to me. It looks more like an attempt to avoid 
 calling a synchronized method if randomNumberGenerator has already been 
 initialized.
 
 A more typical pattern would be
 
 private static Random randomNumberGenerator;
 
 private static synchronized Random getRNG() {
 if (randomNumberGenerator == null) {
 randomNumberGenerator = new Random();
 }
 return randomNumberGenerator;
 }
 
 public static double random() {
 return getRNG().nextDouble();
 }
 
 Comments, please.

(Sorry, I'm late to the party!)

I'm surprised people are still haunted by DCL :) In the correct form, it
has generally negligible synchronization overheads associated with
volatile read, and in return you have no class metadata waste. As in:

  private static volatile Random rng;

  private static Random getRNG() {
if (rng == null) {
   synchronized(Math.class) {
  rng = new Random();
   }
}
return rng;
  }

  public static double random() {
return getRNG().nextDouble();
  }

Also, random() will probably be the scalability bottleneck anyway due to
j.l.Random internal atomics. That means, we do not have to provide the
best possible performance for getRNG(), but rather eliminate the
scalability bottleneck. Holder idiom has a benefit of being sequentially
faster (because JITs elide the class init checks, and read the static
field), but in this case of heavy-weight mechanics in j.u.Random, it is
irrelevant. Hence, we can minimize the downside for class metadata
growth by going with DCL.

I would think the *major* problem the patch should fix is the visibility
of new Random() state in the other threads, because its instance is
being published via the data race -- both correct DCL and Holder idiom
solve that. But then again, our current implementation for Random is
using AtomicLong, which has the inherent thread-safeness, making the
only erroneous scenario impossible.

Bottom-line: commit either correct DCL just to secure ourselves from
the adversarial j.u.Random changes.

-Aleksey.


JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-21 Thread Brian Burkhalter
With respect to this issue

http://bugs.sun.com/view_bug.do?bug_id=6470700

the code of concern from java.lang.Math is

701private static Random randomNumberGenerator;
702
703private static synchronized Random initRNG() {
704Random rnd = randomNumberGenerator;
705return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
706 }

731public static double random() {
732Random rnd = randomNumberGenerator;
733if (rnd == null) rnd = initRNG();
734return rnd.nextDouble();
735}

where the class variable randomNumberGenerator is not used anywhere else in 
the class. The complaint is that this is an instance of the broken 
double-checked locking pattern. While at first glance this might appear to be 
the case, it does not seem so to me. It looks more like an attempt to avoid 
calling a synchronized method if randomNumberGenerator has already been 
initialized.

A more typical pattern would be

private static Random randomNumberGenerator;

private static synchronized Random getRNG() {
if (randomNumberGenerator == null) {
randomNumberGenerator = new Random();
}
return randomNumberGenerator;
}

public static double random() {
return getRNG().nextDouble();
}

Comments, please.

Thanks,

Brian

Re: JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-21 Thread David M. Lloyd

On 8/21/13 5:37 PM, Brian Burkhalter wrote:

With respect to this issue

http://bugs.sun.com/view_bug.do?bug_id=6470700

the code of concern from java.lang.Math is

701private static Random randomNumberGenerator;
702
703private static synchronized Random initRNG() {
704Random rnd = randomNumberGenerator;
705return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
706 }

731public static double random() {
732Random rnd = randomNumberGenerator;
733if (rnd == null) rnd = initRNG();
734return rnd.nextDouble();
735}

where the class variable randomNumberGenerator is not used anywhere else in the class. 
The complaint is that this is an instance of the broken double-checked locking pattern. While at 
first glance this might appear to be the case, it does not seem so to me. It looks more like an 
attempt to avoid calling a synchronized method if randomNumberGenerator has already 
been initialized.

A more typical pattern would be

 private static Random randomNumberGenerator;

 private static synchronized Random getRNG() {
 if (randomNumberGenerator == null) {
 randomNumberGenerator = new Random();
 }
 return randomNumberGenerator;
 }

 public static double random() {
 return getRNG().nextDouble();
 }

Comments, please.


I don't think you'd want to introduce the overhead of synchronization 
here.  It may be better in this case to use this kind of lazy init pattern:


static final class Holder {
static final Random RNG = new Random();
}

public static double random() {
return Holder.RNG.nextDouble();
}

--
- DML


Re: JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-21 Thread Brian Burkhalter
On Aug 21, 2013, at 5:01 PM, David M. Lloyd wrote:

 I don't think you'd want to introduce the overhead of synchronization here.

No, I don't. My example code was just that.

 It may be better in this case to use this kind of lazy init pattern:
 
static final class Holder {
static final Random RNG = new Random();
}
 
public static double random() {
return Holder.RNG.nextDouble();
}

Thanks for the cleaner suggestion.

Brian


Re: JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-21 Thread Steven Schlansker

On Aug 21, 2013, at 4:37 PM, Brian Burkhalter brian.burkhal...@oracle.com 
wrote:

 With respect to this issue
 
 http://bugs.sun.com/view_bug.do?bug_id=6470700
 
 the code of concern from java.lang.Math is
 
 701private static Random randomNumberGenerator;
 702
 703private static synchronized Random initRNG() {
 704Random rnd = randomNumberGenerator;
 705return (rnd == null) ? (randomNumberGenerator = new Random()) : 
 rnd;
 706 }
 
 731public static double random() {
 732Random rnd = randomNumberGenerator;
 733if (rnd == null) rnd = initRNG();
 734return rnd.nextDouble();
 735}
 
 where the class variable randomNumberGenerator is not used anywhere else in 
 the class. The complaint is that this is an instance of the broken 
 double-checked locking pattern. While at first glance this might appear to be 
 the case, it does not seem so to me. It looks more like an attempt to avoid 
 calling a synchronized method if randomNumberGenerator has already been 
 initialized.


This looks very much like the Broken multithreaded version from
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

// Broken multithreaded version
// Double-Checked Locking idiom
class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
if (helper == null) 
  synchronized(this) {
if (helper == null) 
  helper = new Helper();
  }
return helper;
}
  // other functions and members...
  }


Unfortunately, that code just does not work in the presence of either 
optimizing compilers or shared memory multiprocessors.



Re: JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-21 Thread Vitaly Davidovich
There's a significant difference here: Random reads the field into a local
and then operates only on the local.  Looking at the code, I only see one
possible (bizarre) circumstance where you can hit NPE.  If code was
transformed to:

static double random() {
  Random rnd = randomNumberGenerator; // assume null is read
  if (randomNumberGenerator == null) ... // note the field is re-read
instead of local, and assume it's not null now
 return rnd.nextDouble(); // NPE
}

I don't see a case where any sane compiler would do this but I think it's
legal transformation given that the field is non-volatile and single
threaded execution would not detect difference.  Unless phantom reads
cannot be introduced even for plain fields, in which case I don't see how
NPE can occur.

Having said that, David's suggestion is cleaner anyway.

Sent from my phone
On Aug 21, 2013 8:36 PM, Steven Schlansker stevenschlans...@gmail.com
wrote:


 On Aug 21, 2013, at 4:37 PM, Brian Burkhalter brian.burkhal...@oracle.com
 wrote:

  With respect to this issue
 
  http://bugs.sun.com/view_bug.do?bug_id=6470700
 
  the code of concern from java.lang.Math is
 
  701private static Random randomNumberGenerator;
  702
  703private static synchronized Random initRNG() {
  704Random rnd = randomNumberGenerator;
  705return (rnd == null) ? (randomNumberGenerator = new Random())
 : rnd;
  706 }
 
  731public static double random() {
  732Random rnd = randomNumberGenerator;
  733if (rnd == null) rnd = initRNG();
  734return rnd.nextDouble();
  735}
 
  where the class variable randomNumberGenerator is not used anywhere
 else in the class. The complaint is that this is an instance of the broken
 double-checked locking pattern. While at first glance this might appear to
 be the case, it does not seem so to me. It looks more like an attempt to
 avoid calling a synchronized method if randomNumberGenerator has already
 been initialized.


 This looks very much like the Broken multithreaded version from
 http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

 // Broken multithreaded version
 // Double-Checked Locking idiom
 class Foo {
   private Helper helper = null;
   public Helper getHelper() {
 if (helper == null)
   synchronized(this) {
 if (helper == null)
   helper = new Helper();
   }
 return helper;
 }
   // other functions and members...
   }


 Unfortunately, that code just does not work in the presence of either
 optimizing compilers or shared memory multiprocessors.




Re: JDK 8 RFC 6470700: Math.random() / Math.initRNG() uses double checked locking

2013-08-21 Thread Mike Duigou
On Aug 21 2013, at 17:01 , David M. Lloyd wrote:

 On 8/21/13 5:37 PM, Brian Burkhalter wrote:
 With respect to this issue
 
 http://bugs.sun.com/view_bug.do?bug_id=6470700
 
 the code of concern from java.lang.Math is
 
 701private static Random randomNumberGenerator;
 702
 703private static synchronized Random initRNG() {
 704Random rnd = randomNumberGenerator;
 705return (rnd == null) ? (randomNumberGenerator = new Random()) : 
 rnd;
 706 }
 
 731public static double random() {
 732Random rnd = randomNumberGenerator;
 733if (rnd == null) rnd = initRNG();
 734return rnd.nextDouble();
 735}
 
 where the class variable randomNumberGenerator is not used anywhere else 
 in the class. The complaint is that this is an instance of the broken 
 double-checked locking pattern. While at first glance this might appear to 
 be the case, it does not seem so to me. It looks more like an attempt to 
 avoid calling a synchronized method if randomNumberGenerator has already 
 been initialized.
 
 A more typical pattern would be
 
 private static Random randomNumberGenerator;
 
 private static synchronized Random getRNG() {
 if (randomNumberGenerator == null) {
 randomNumberGenerator = new Random();
 }
 return randomNumberGenerator;
 }
 
 public static double random() {
 return getRNG().nextDouble();
 }
 
 Comments, please.
 
 I don't think you'd want to introduce the overhead of synchronization here.  
 It may be better in this case to use this kind of lazy init pattern:
 
static final class Holder {
static final Random RNG = new Random();
}
 
public static double random() {
return Holder.RNG.nextDouble();
}
 
 -- 
 - DML


David's suggestion seems very reasonable.


Mike