我正在学习随机数生成和概念的概念。 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)。
答案 0 :(得分:4)
首先,您应该使用new Random()
,因为它看起来like this(详细信息取决于Java版本):
public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
即。它已经使用nanoTime()
和确保具有相同nanoTime()
结果的不同主题获得不同的种子,new Random(System.nanoTime())
不会。
(编辑:Pyranja指出这是Java 6中的一个错误,但它是固定的in 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,由于the birthday paradox,某些数字相同的概率非常高。
第三,如果您只想要唯一ID,则可以使用AtomicInteger
计数器而不是随机数。或者如果你想要一个随机的部分开头,也要附加一个计数器来保证唯一性。
答案 1 :(得分:2)
此类允许您从特定范围获取非重复值,直到使用整个范围。使用范围后,它将重新初始化。
Class附带了一个简单的测试。
如果您想使类线程安全,只需将synchronized
添加到nextInt()
声明。
然后,您可以使用单例模式或仅使用静态变量从多个线程访问生成器。这样,所有线程都将使用相同的对象和相同的唯一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());
}
}
}
答案 2 :(得分: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()