3

我是一种学习java中随机数生成和多线程的概念。

这个想法是在特定毫秒内不生成范围为 1000 的重复随机数(考虑到不超过 50 个数据,以多线程方式将在一毫秒内处理)。这样在特定时间生成的随机数列表是唯一的。你能给我任何想法,因为我最终会在特定的毫秒内生成几个重复的随机数(而且,有相当大的概率)。

我尝试了以下失败的事情。

Random random = new Random(System.nanoTime());
double randomNum = random.nextInt(999);

//

int min=1; int max=999;
double randomId = (int)Math.abs(math.Random()* (max - min + 1) + min);

//

Random random = new Random(System.nanoTime()); // also tried new Random();
double randomId = (int)Math.abs(random.nextDouble()* (max - min + 1) + min);

当我附加正在生成的时间戳时,在多线程环境中,我看到为 5000 多个唯一数据生成(2-4 次)相同的 id(大约 8-10)。

4

3 回答 3

4

首先,您应该使用new Random(),因为它看起来像这样(详细信息取决于 Java 版本):

 public Random() { this(++seedUniquifier + System.nanoTime()); }
 private static volatile long seedUniquifier = 8682522807148012L;

即它已经利用nanoTime() 确保具有相同nanoTime()结果的不同线程获得不同的种子,但new Random(System.nanoTime())事实并非如此。

(编辑:Pyranja 指出这是 Java 6 中的一个错误,但它已在 Java 7 中修复:

public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

private static final AtomicLong seedUniquifier
    = new AtomicLong(8682522807148012L);

)

其次,如果你生成 50 个从 1 到 1000 的随机数,由于生日悖论,一些数字相同的概率非常高。

第三,如果你只想要唯一的 id,你可以只使用AtomicInteger计数器而不是随机数。或者,如果您想要一个随机部分开始,请附加一个计数器以保证唯一性。

于 2013-10-01T09:11:17.583 回答
2

此类将允许您从某个范围获取非重复值,直到使用整个范围。一旦使用范围,它将重新初始化。

课程伴随着一个简单的测试。

如果要使类线程安全,只需添加synchronizednextInt()声明中。

然后,您可以使用单例模式或仅使用静态变量从多个线程访问生成器。这样,您的所有线程都将使用相同的对象和相同的唯一 ID 池。

public class NotRepeatingRandom {
    int size;
    int index;
    List<Integer> vals;
    Random gen = new Random();

    public NotRepeatingRandom(int rangeMax) {
      size = rangeMax;
      index = rangeMax; // to force initial shuffle
      vals = new ArrayList<Integer>(size);
      fillBaseList();
    }

    private void fillBaseList() {
      for (int a=0; a<size; a++) {
        vals.add(a);
      }
    }

    public int nextInt() {
      if (index == vals.size()) {
          Collections.shuffle(vals);
          index = 0;
      }
      int val = vals.get(index);
      index++;      
      return val;
    }

    public static void main(String[] args) {
        NotRepeatingRandom gen = new NotRepeatingRandom(10);
        for (int a=0; a<30; a++) {
            System.out.println(gen.nextInt());
        }
    }
}
于 2013-10-01T09:04:56.960 回答
0

如果我正确理解您的问题,多个线程同时创建自己的 Random 类实例,并且所有线程都生成相同的随机数?生成相同的数字,因为所有随机实例都是同时创建的,即具有相同的种子。

要解决此问题,请仅创建 Random 类的一个实例,该实例由所有线程共享,以便所有线程在同一实例上调用 nextDouble()。Random.nextDouble() 类是线程安全的,每次调用都会隐式更新其种子。

//create only one Random instance, seed is based on current time
public static final Random generator= new Random();

现在所有线程都应该使用相同的实例:

double random=generator.nextDouble() 
于 2013-10-01T09:16:12.523 回答