您的位置:首页 > 编程语言 > Java开发

每天一个java类之Random

2014-04-28 20:02 351 查看
其实没法做到每天一个啦,就几天一个好了

主要是因为面试时,经常被问到JVM源码,而我确实看的较少

那就补补吧。

今天是Random,去微软面试的时候,三面的面试官让写一个Random类,当然,有特殊要求的

恍惚间,我不记得Random怎么实现的,连怎么用的都模糊了。。。

Sigh~

Random

Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术的3.2.1节)

如果两个Random实例使用相同的种子,并且调用同样的函数,那么生成的sequence是相同的

也可以调用Math.random()生成随机数

Random实例是线程安全的,但是并发使用Random实例会影响效率,可以考虑使用ThreadLocalRandom变量。

Random实例不是安全可靠的加密,可以使用java.security.SecureRandom来提供一个可靠的加密。

Random implements Serializable 可序列化的

AtomicLong seed 原子变量

long multiplier = 0x5DEECE66DL;

long addend = 0xBL;

long mask = (1L << 48) -1 ;

AtomicLong seedUniquifiler;

Random(){

  this( seedUniquifier() ^ System.nanoTime() )

}

static long seedUniquifier(){

    for(;;){

         long current = seedUniquifier.get();

         long next = current * 181783497276652981L;

         if( seedUniquifier.compareAndSet(current,next))

                return next;

    } 

}

// seed是随机生成器的初始值,由next()维护这个随机生成器

Random(long seed){

   if(getClass() == Random.class)

       this.seed =  new AtomicLong(initialScramble(seed));

   else{

       this.seed = new AtomicLong();

       setSeed(seed);

   }

}

static long initialScramble(long seed){

   return (seed ^ multiplier )  & mask;

}

重新设置seed, setSeed只使用48bit。并清空hasNextNextGussian标志

synchronize public void setSeed(long seed){

   this.seed.set(initialScramble(seed));

   hasNextNextGaussian = false;

}

生成下一个伪随机数,子类需要重写这个方法。

使用一个线性同余方程,生成伪随机数

protected int next(int bits){

     long oldSeed,nextSeed;

    AtomicLong seed = this.seed;

    do {

          oldSeed = seed.get();

          nextSeed = (oldSeed * multiplier + addend) & mask;

     }while( ! seed.compareAndSet(oldSeed,nextSeed) ) ;

     return (int)(nextseed >>> (48-bits));

}

随机生成一个字节数组,并存放到用户传进来的bytes数组中。

public void nextBytes(byte[]bytes){

    for(int i = 0 ,len = bytes.length; i < len ;  ){

           for(int rnd = nextInt(), n = Math.min(len-i,Integer.SIZE/Byte.SIZE); n- - >0; rnd >>= Byte.SIZE)

                      bytes[i++] = (byte) rnd;

              

    }

}

要求2 ^ 32个证书生成的概率相等

int nextInt(){

   return next(32);

}

生成一个伪随机数,等概率的一致分布0~n: [0-n)

要求n个数以等概率生成

该方法只给出一个approximately an unbiased source of independently chosen bits

对于2的幂次,给出一个corrent number of high-order bits from 伪随机生成器。

否则,返回一个correct number of low-order bits

int nextInt(int n){

   if (n <= 0)

          throw new IllegalArgumentException("n must be positive");

   if ((n & -n ) == n) //n是2 的幂次

          return (int ) ( (n * (long) next(31 )) >> 31 );

  int bits,val;

  do{

        bits = next(31);

        val = bits % n; 

   }while( bits - val + (n-1)  < 0 );

   return val;

}

public long nextLong(){

   return ((long) (next(32)) << 32 )  + next(32);

}

boolean nextBoolean(){

    return next(1) != 0;

}

float nextFloat(){

   return next(24)/((float) (1 << 24));

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  random 线程安全