[concurrency-interest] Funny ThreadLocalRandom Bug in Random :-)

Dr Heinz M. Kabutz heinz at javaspecialists.eu
Wed Jan 4 14:18:54 EST 2012


What started as a quest to write a little Phaser demo, ended up as a 
chase through the Java 7 source code to find a fun bug.  Turns out that 
in the version of Java 7 that I am using (on the Mac OS X, unofficial 
build, build 1.7.0-ea-b221), there is a bug in Random.  In the 
constructor, it should have said:

    public Random(long seed) {
        this.seed = new AtomicLong();
        setSeed(initialScramble(seed));
    }

But instead, they just do:

    public Random(long seed) {
        this.seed = new AtomicLong(initialScramble(seed));
    }

As a result, the setSeed() method in the ThreadLocalRandom is never called!

In other words, the seed will always be zero and all ThreadLocalRandom 
instances will give back the same values.  Every time.

Here is the Phaser demo I was talking about.  It makes all the buttons 
change their background color for a random amount of time.  Here they 
have to create their own instance of Random, since ThreadLocalRandom 
does not work correctly.  Enjoy :-)



import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author Heinz Kabutz
 */
public class Blinker extends JFrame {
  private static final boolean USE_THREAD_LOCAL_RANDOM = false;

  public Blinker() {
    setLayout(new FlowLayout());
  }

  private void addButtons(int buttons, final int blinks) {
    final Phaser phaser = new Phaser(buttons) {
      protected boolean onAdvance(int phase, int registeredParties) {
        return phase >= blinks - 1 || registeredParties == 0;
      }
    };

    for (int i = 0; i < buttons; i++) {
      final JComponent comp = new JButton("Button " + i);
      comp.setOpaque(true);
      changeColor(comp, Color.WHITE);
      add(comp);
      new Thread() {
        public void run() {
          final Random rand =
              USE_THREAD_LOCAL_RANDOM ? ThreadLocalRandom.current() : 
new Random();
          try {
            int phases = 0;
            do {
              System.out.println(++phases);
              Color newColor = new Color(rand.nextInt());
              changeColor(comp, newColor);
              Thread.sleep(100 + rand.nextInt(3000));
              changeColor(comp, Color.WHITE);
              Toolkit.getDefaultToolkit().beep();
              Thread.sleep(2000);
              phaser.arriveAndAwaitAdvance();
            } while (!phaser.isTerminated());
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
          }
        }
      }.start();
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  private void changeColor(final JComponent comp, final Color color) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        comp.setBackground(color);
        invalidate();
        repaint();
      }
    });
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        Blinker blinker = new Blinker();
        blinker.addButtons(10, 3);
        blinker.pack();
        blinker.setVisible(true);
        blinker.setDefaultCloseOperation(EXIT_ON_CLOSE);
      }
    });
  }
}

Regards

Heinz
-- 
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz







More information about the Concurrency-interest mailing list