📜  Java的Random 与 ThreadLocalRandom 类

📅  最后修改于: 2021-09-15 01:25:02             🧑  作者: Mango

Java.util 包的 Random 类用于生成伪随机数流。它使用 48 位种子,通过实施线性同余公式对其进行修改。线性同余公式的一般形式是 a n+1 = k * a n + c (mod m) 其中 a 0是种子,a 1 , a 2 , … a n , a n+1是随机数和k、c、m 是常数。

如果我们创建Random类的两个实例使用相同的种子值和调用的方法每一个相同的序列,它们都将返回数字相同的序列s。此属性由为此类定义的特定算法强制执行。该算法使用受保护的实用方法,该方法在调用时最多可以给出 32 个伪随机生成的位。随机的实例是线程安全的。但是,如果跨线程使用相同的实例,它们可能会发生争用并导致性能不佳。 Random 实例在密码学上不是安全的,因此不应用于对安全敏感的应用程序。

句法:

public class Random extends Object implements Serializable

让我们举个例子,在下面给出的程序中,我们有 Random 类的三个实例。前两个具有传递给其构造函数的相同种子值。当我们使用 Random 类的 nextInt() 方法时,这会导致生成相同的数字。但是当我们更改种子的值并使用它来创建第三个实例时,生成的数字是不同的。这个例子清楚地证明了上述事实,即如果使用相同的种子值并且对两者使用相同的方法,则实例会生成相同的数字序列。

Java
// Java Program to illustrate Random class
  
// Importing Random class from java.util utility package
import java.util.Random;
  
// Class
// Main clas extending to parent Random class
public class RandomNumbers extends Random {
  
    // Main driver method
    public static void main(String[] args)
    {
  
        // Initialise a seed value
        long seed = 18;
  
        // Create an instance of Random using the seed value
        Random r1 = new Random(seed);
  
        // Prinitng the primitive datatype-integer
        // by parsing using nextInt() method
        System.out.println(r1.nextInt());
  
        // Create a different instance of Random using the
        // same seed value
        Random r2 = new Random(seed);
  
        // Again, prinitng the primitive datatype-integer
        // by parsing using nextInt() method
        System.out.println(r2.nextInt());
  
        // Change the seed value to
        // some other random value
        seed = 34;
  
        // Create a new instance using the updated seed
        // value
        Random r3 = new Random(seed);
  
        // Lastly prinitng the primitive datatype-integer
        // by parsing using nextInt() method
        System.out.println(r3.nextInt());
    }
}


Java
// Java Program to Illustrate ThreadLocalRandom class
  
// Importing ThreadLocalRandom class from utility package
// named java.util.concurrent package
import java.util.concurrent.ThreadLocalRandom;
  
// Class 1
// Main class extending parent class- Thread
class ThreadLocalRandomNumbers extends Thread {
  
    // Method 1
    // The run() method of the Thread class
    // Must be defined by every class that extends it
    public void run()
    {
  
        // Try block to check for exceptions
        try {
  
            // Initializaing a seed value to
            // some random integer value
            int seed = 10;
  
            // Getting the current seed by
            // calling over ThreadLocalRandom class and
            // storing it in a integer variable
            int r
                = ThreadLocalRandom.current().nextInt(seed);
  
            // Printing the generated number r
            // The thread id is obtained using getId()
            System.out.println(
                "Thread " + Thread.currentThread().getId()
                + " generated " + r);
        }
  
        // Catch block to catch the exceptions
        catch (Exception e) {
  
            // Dipslay message on the console if
            // the exception/s occur
            System.out.println("Exception");
        }
    }
  
    // Method 2
    // Main driver method
    public static void main(String[] args)
    {
  
        // Create two threads
        ThreadLocalRandomNumbers t1
            = new ThreadLocalRandomNumbers();
        ThreadLocalRandomNumbers t2
            = new ThreadLocalRandomNumbers();
  
        // Starting th above created threads
        // using the start() method
        t1.start();
        t2.start();
    }
}


输出

-1148559096
-1148559096
-1167027043

现在讨论下一个类,即我们的 ThreadLocalRandom 类

Java.util 包中的ThreadLocalRandom 类也用于生成伪随机数流。它是上面讨论的 Random 类的子类。顾名思义,此类生成与当前线程隔离的随机数。 ThreadLocalRandom 使用内部生成的种子值初始化,该值不可修改。使用 ThreadLocalRandom 而不是 Random 的共享实例将导致低争用和开销。 ThreadLocalRandom 就像它的父类一样,在密码学上并不安全。

句法:

public class ThreadLocalRandom extends Random

实现:让我们假设我们在主线程中创建两个简单的线程。在 run() 方法中,我们调用ThreadLocalRandom.current.nextInt() 。两个线程使用相同的种子值,即 10,但给出不同的结果,因为对nextInt()的调用被线程执行隔离。

例子

Java

// Java Program to Illustrate ThreadLocalRandom class
  
// Importing ThreadLocalRandom class from utility package
// named java.util.concurrent package
import java.util.concurrent.ThreadLocalRandom;
  
// Class 1
// Main class extending parent class- Thread
class ThreadLocalRandomNumbers extends Thread {
  
    // Method 1
    // The run() method of the Thread class
    // Must be defined by every class that extends it
    public void run()
    {
  
        // Try block to check for exceptions
        try {
  
            // Initializaing a seed value to
            // some random integer value
            int seed = 10;
  
            // Getting the current seed by
            // calling over ThreadLocalRandom class and
            // storing it in a integer variable
            int r
                = ThreadLocalRandom.current().nextInt(seed);
  
            // Printing the generated number r
            // The thread id is obtained using getId()
            System.out.println(
                "Thread " + Thread.currentThread().getId()
                + " generated " + r);
        }
  
        // Catch block to catch the exceptions
        catch (Exception e) {
  
            // Dipslay message on the console if
            // the exception/s occur
            System.out.println("Exception");
        }
    }
  
    // Method 2
    // Main driver method
    public static void main(String[] args)
    {
  
        // Create two threads
        ThreadLocalRandomNumbers t1
            = new ThreadLocalRandomNumbers();
        ThreadLocalRandomNumbers t2
            = new ThreadLocalRandomNumbers();
  
        // Starting th above created threads
        // using the start() method
        t1.start();
        t2.start();
    }
}
输出
Thread 12 generated 7
Thread 11 generated 0

现在我们已经完成了对这两个类的讨论,并对它们有了充分的了解。现在通过总结它们之间的差异来结束这篇文章。

Random ThreadLocalRandom
If different threads use the same instance of Random it results in contention and consequent performance degradation. There is no contention because the random numbers generated are local to the current thread.
Uses Linear Congruential Formula to modify its seed value. The Random generator is initialized using an internally generated seed.
Useful in applications where each thread has its own set of Random instances to use. Useful in applications where multiple threads use random numbers in parallel in thread pools.
This is the Parent class. This is the Child class.