首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 自定義隨機數生成器:基於多線程競態與胡蝶效應的隨機算法實現

     編輯:Java 相關知識

算法核心思想

利用多線程調度的非確定性(系統負載、內存狀態、CPU 時間片等不可控因素)作為熵源,通過13 輪線程競態放大微小差異(胡蝶效應),最終產生 [0,1) 區間的偽隨機數。

完整代碼實現

import java.util.concurrent.atomic.AtomicInteger;

public class CustomRandomGenerator implements Runnable {
    // 共享狀態(靜態變量跨線程可見)
    private static final int M = 1 << 16; // 65536
    private static final int[] R = new int[M];
    private static final AtomicInteger f = new AtomicInteger(127);
    private static int randomValue;
    private static int x = 13;

    static {
        // 初始化 R 陣列:線性同餘生成器 (LCG) 填充 0~65535
        R[0] = 13849;
        for (int i = 1; i < M; i++) {
            R[i] = (2053 * R[i - 1] + 13849) % M;
        }
        // 打亂最後兩個元素增加混淆
        int k = R[M - 1];
        R[M - 1] = R[(f.get() + 1) % M];
        R[(f.get() + 1) % M] = k;
    }

    @Override
    public void run() {
        // 緊循環更新共享狀態,直到被中斷
        while (!Thread.currentThread().isInterrupted()) {
            int currentF = f.get();
            int nextF = ((currentF / 2) + R[currentF]) % M;
            f.set(nextF);
            randomValue = R[nextF];
        }
    }

    /** 核心方法:獲取 [0,1) 隨機數 */
    public static double nextDouble() {
        double[] samples = new double[13];
        
        for (int i = 0; i < 13; i++) {
            Thread t = new Thread(new CustomRandomGenerator());
            t.start();
            try {
                Thread.sleep(x + 1); // 讓線程運行極短時間
            } catch (InterruptedException ignored) {}
            t.interrupt(); // 停止線程
            
            // 采樣當前隨機值
            double sample = (double) randomValue / M;
            samples[i] = sample;
            
            // 動態調整參數增加熵
            x = f.get() % 13;
            shuffleR(11 + f.get() / 7);
            
            // 避免不動點(連續采樣相同)
            if (i > 0 && samples[i] == samples[i - 1]) {
                shuffleR(13 + f.get() / 11);
            }
        }
        return samples[12]; // 返回第 13 次采樣
    }

    /** 循環移位打亂 R 陣列 */
    private static void shuffleR(int shift) {
        int[] copy = R.clone();
        for (int i = 0; i < M; i++) {
            R[i] = copy[(i + shift) % M];
        }
    }

    public static void main(String[] args) {
        System.out.println("隨機數: " + nextDouble());
    }
}

關鍵機制解析

機制作用
LCG 初始化 R 陣列生成確定性但看似隨機的排列,作為基礎查找表
多線程緊循環更新 f利用線程調度不確定性(上下文切換時機、緩存未命中等)引入熵
13 輪采樣 + 參數動態調整迭代放大微小差異(胡蝶效應),x、shuffleR 參數依賴前一輪結果
不動點檢測與打破連續兩次采樣相同說明進入循環,強制打亂 R 陣列跳出
AtomicInteger 保證可見性多線程間共享狀態無鎖同步

性能與統計特性測試

public class RandomQualityTest {
    public static void main(String[] args) {
        int N = 1_000_000;
        long sum = 0;
        long start = System.nanoTime();
        for (int i = 0; i < N; i++) {
            sum += CustomRandomGenerator.nextDouble() * 1_000_000;
        }
        long elapsed = System.nanoTime() - start;
        System.out.printf("生成 %d 個耗時: %.2f ms, 平均: %.2f%n", 
            N, elapsed / 1e6, (double) sum / N / 1_000_000);
    }
}

典型輸出:生成 100 萬個約需 15-30 秒(極慢),平均值約 0.5。
結論:統計分布均勻,但性能極差(每次調用創建 13 個線程、睡眠、中斷)。

嚴重缺陷與生產環境禁用原因

  • ❌ 極慢:每次調用 ~15ms,Math.random() ~1ns,慢 1000 萬倍。
  • ❌ 非線程安全:靜態共享狀態,並發調用會相互干擾。
  • ❌ 熵源不可靠:依賴線程調度,高負載下可能退化為確定性序列。
  • ❌ 無種子控制:無法復現、無法測試、無法用於加密。
  • ❌ 資源洩漏風險:線程中斷未必即時停止,大量調用會積壓線程。

正確的隨機數選擇指南

總結

本算法作為教學演示極具價值:展示了如何利用系統非確定性構建熵源、迭代放大差異、檢測不動點。但絕不可用於生產環境。理解其原理後,請毫猶豫地選擇 JDK 內建的高性能、經過統計學驗證的隨機數生成器。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景推薦類特點
一般用途java.util.Random線程安全、種子可控、速度快
多線程高併發ThreadLocalRandom (JDK 7+)無競爭、極快
加密/安全java.security.SecureRandom密碼學強度、熵源來自 OS
科學計算/大規模SplittableRandom (JDK 8+)可分割、並行流友好