每个线程一个随机实例,由原始Random实例播种以获得可重复性

时间:2016-08-31 15:46:10

标签: java random distribution uniform-distribution

我需要进行1000计算,每个计算基于一个随机数。 整个运行需要可重现

在单线程环境中,我只是根据种子创建随机数,并将其用于每次计算:

Random random = new Random(37);
for (Calculation c : calculations) {
    c.doCalculation(r.nextInt());
}

在多线程环境中,我有10个线程,我有一个种子随机种子线程Random's:

Random initRandom = new Random(37);
for (List<Calculation> p : calculationPartitions) {
    final Random threadRandom = new Random(initRandom.nextLong());
    executorService.submit(() -> {
        for (Calculation c : p) {
            c.doCalculation(threadRandom.nextInt());
        }
    });
}
// Merge the calculation results back in the same order as the calculationPartitions
...

这是一个好主意吗?一般来说它仍然是均匀分布的随机数吗?每个threadRandominitRandom播种的事实是否会破坏统一分布?

由于可重复的原因,我无法共享1个全局随机数,因为某些线程在某些运行中可能比其他线程运行得更快,因此它们不会总是以相同的顺序调用全局随机数(并且争用可能会导致性能下降)。 / p>

2 个答案:

答案 0 :(得分:1)

您将通过Random获得均匀的数字分布,但是不保证列表中每个Calculation对象列表的运行顺序,因此如果这些顺序将结果传递给共享列表,则顺序可能会因运行而异。

答案 1 :(得分:1)

特别是关于均匀分布,似乎每10个像素有1个随机位置:

distribution

哦等等,每1个像素有1个随机位置,种子线程方法看起来更好!?在一个完美的均匀分布(尺寸250000),它将全黑:

enter image description here

左:

public class SingleRandomProof extends JFrame {

    public static final int WIDTH = 500;
    public static final int HEIGHT = 500;
    public static final int SIZE = WIDTH * HEIGHT;

    public static void main(String[] args) {
        SingleRandomProof proof = new SingleRandomProof();
        proof.pack();
        proof.setVisible(true);
        proof.doCalc();
    }

    private JLabel panel;

    public SingleRandomProof() throws HeadlessException {
        super("1 random");
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        panel = new JLabel(new ImageIcon(image));
        setContentPane(panel);
    }

    private void doCalc() {
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.BLACK);
        Random r = new Random(37);
        for (int i = 0; i < SIZE; i++) {
            int position = r.nextInt(SIZE);
            g.fillRect(position % HEIGHT, position / HEIGHT, 1, 1);
        }
        panel.setIcon(new ImageIcon(image));
    }

}

右:

public class SeededThreadRandomProof extends JFrame {

    public static final int WIDTH = 500;
    public static final int HEIGHT = 500;
    public static final int SIZE = WIDTH * HEIGHT;

    public static void main(String[] args) {
        SeededThreadRandomProof proof = new SeededThreadRandomProof();
        proof.pack();
        proof.setVisible(true);
        proof.doCalc();
    }

    private JLabel panel;

    public SeededThreadRandomProof() throws HeadlessException {
        super("10 seeded randoms");
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        panel = new JLabel(new ImageIcon(image));
        setContentPane(panel);
    }

    private void doCalc() {
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.BLACK);
        Random initRandom = new Random(37);
        for (int j = 0; j < 10; j++) {
            Random r = new Random(initRandom.nextLong());
            for (int i = 0; i < SIZE / 10; i++) {
                int position = r.nextInt(SIZE);
                g.fillRect(position % HEIGHT, position / HEIGHT, 1, 1);
            }
        }
        panel.setIcon(new ImageIcon(image));
    }

}