最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問題

 更新時間:2021年12月22日 09:47:55   作者:磨唧  
這篇文章主要介紹了解決SecureRandom.getInstanceStrong()引發(fā)的線程阻塞問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

1. 背景介紹

sonar掃描到使用Random隨機函數(shù)不安全, 推薦使用SecureRandom替換之, 當使用SecureRandom.getInstanceStrong()獲取SecureRandom并調用next方式時, 在生產環(huán)境(linux)產生較長時間的阻塞, 但開發(fā)環(huán)境(windows7)并未重現(xiàn)

2. 現(xiàn)象展示

使用測試代碼:

package com.youai.test;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class TestRandom {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        System.out.println("start.....");
        long start = System.currentTimeMillis();
        SecureRandom random = SecureRandom.getInstanceStrong();
        for(int i = 0; i < 100; i++) {
            System.out.println("第" + i + "個隨機數(shù).");
            random.nextInt(10000);
        }
        System.out.println("finish...time/ms:" + (System.currentTimeMillis() - start));
    }
}

2.1 windows7下運行結果

第94個隨機數(shù).
第95個隨機數(shù).
第96個隨機數(shù).
第97個隨機數(shù).
第98個隨機數(shù).
第99個隨機數(shù).
finish...time/ms:100

windows下未出現(xiàn)明顯阻塞現(xiàn)象, 耗時100ms

2.2 centos7下運行結果

第52個隨機數(shù).
第53個隨機數(shù).
第54個隨機數(shù).
第55個隨機數(shù).
第56個隨機數(shù).
第57個隨機數(shù).
第58個隨機數(shù).
第59個隨機數(shù).
第60個隨機數(shù).
第61個隨機數(shù).
第62個隨機數(shù).
第63個隨機數(shù).
第64個隨機數(shù).
...

linux下運行阻塞在第65次獲取隨機數(shù).(如果實驗結果未阻塞, 可以嘗試增加獲取隨機數(shù)的次數(shù))

3. 現(xiàn)象分析

3.1 linux阻塞分析

通過

jstack -l <你的java進程>

得到如下堆棧信息

"main" #1 prio=5 os_prio=0 tid=0x00007f894c009000 nid=0x1129 runnable [0x00007f8952aa9000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
at sun.security.provider.NativePRNG$RandomIO.readFully(NativePRNG.java:424)
at sun.security.provider.NativePRNG$RandomIO.ensureBufferValid(NativePRNG.java:525)
at sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:544)
- locked <0x000000076c77cb28> (a java.lang.Object)
at sun.security.provider.NativePRNG$RandomIO.access$400(NativePRNG.java:331)
at sun.security.provider.NativePRNG$Blocking.engineNextBytes(NativePRNG.java:268)
at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
at java.security.SecureRandom.next(SecureRandom.java:491)
at java.util.Random.nextInt(Random.java:390)
at TestRandom.main(TestRandom.java:12)

可以看到main線程阻塞在了java.io.FileInputStream.readBytes(Native Method)這個讀取文件的IO處.

對NativePRNG的部分關鍵源碼進行分析:

// name of the pure random file (also used for setSeed())
private static final String NAME_RANDOM = "/dev/random";
// name of the pseudo random file
private static final String NAME_URANDOM = "/dev/urandom";
private static RandomIO initIO(final Variant v) {
    return AccessController.doPrivileged(
        new PrivilegedAction<RandomIO>() {
            @Override
            public RandomIO run() {
                File seedFile;
                File nextFile;
                switch(v) {
                //...忽略中間代碼
                case BLOCKING: // blocking狀態(tài)下從/dev/random文件中讀取
                    seedFile = new File(NAME_RANDOM);
                    nextFile = new File(NAME_RANDOM);
                    break;
                case NONBLOCKING: // unblocking狀態(tài)下從/dev/urandom文件中讀取數(shù)據(jù)
                    seedFile = new File(NAME_URANDOM);
                    nextFile = new File(NAME_URANDOM);
                    break;
               	//...忽略中間代碼
                try {
                    return new RandomIO(seedFile, nextFile);
                } catch (Exception e) {
                    return null;
                }
            }
    });
}
// constructor, called only once from initIO()
private RandomIO(File seedFile, File nextFile) throws IOException {
    this.seedFile = seedFile;
    seedIn = new FileInputStream(seedFile);
    nextIn = new FileInputStream(nextFile);
    nextBuffer = new byte[BUFFER_SIZE];
}
private void ensureBufferValid() throws IOException {
     long time = System.currentTimeMillis();
     if ((buffered > 0) && (time - lastRead < MAX_BUFFER_TIME)) {
         return;
     }
     lastRead = time;
     readFully(nextIn, nextBuffer);
     buffered = nextBuffer.length;
}

從源代碼分析, 發(fā)現(xiàn)導致阻塞的原因是因為從/dev/random中讀取隨機數(shù)導致, 可以通過如下代碼驗證:

import java.io.FileInputStream;
import java.io.IOException;
public class TestReadUrandom {
    public static void main(String[] args) throws IOException {
        System.out.println("start.....");
        for(int i = 0; i < 100; i++) {
            System.out.println("第" + i + "次讀取隨機數(shù)");
            FileInputStream inputStream = new FileInputStream("/dev/random");
            byte[] buf = new byte[32];
            inputStream.read(buf, 0, buf.length);
        }
    }
}

上述代碼在linux環(huán)境下同樣會產生阻塞.

通過hotspot源碼分析, java通過c調用操作系統(tǒng)的讀取文件api, 通過一個c代碼的案例論證:

#include <stdio.h>
#include <fcntl.h>
int main() {
    int randnum = 0;
    int fd = open("/dev/random", O_RDONLY);
    if(fd == -1) {
        printf("open error.\n");
        return 1;
    }
    int i = 0;
    for(i = 0; i < 100; i++) {
        read(fd, (char *)&randnum, sizeof(int));
        printf("random number = %d\n", randnum);
    }
    close(fd);
    return 0;
}

這個例子再次論證了讀取/dev/random會導致阻塞

3.2 windows下運行結果分析

  • NativePRNG.java這個文件在linux和windows下的環(huán)境中實現(xiàn)不同
  • windows的調用堆棧過程

windows調用過程

  • windows在通過SecureRandom.getInstanceStrong()獲取隨機數(shù)的過程, 并沒有使用到NativePRNG, 而是最終調用sun.security.mscapi.PRNG#generateSeed的native方法, 所以windows并沒有明顯的阻塞現(xiàn)象(但明顯比 new SecureRandom()生成的對象產生隨機數(shù)要慢許多).
  • sun.security.mscapi.PRNG#generateSeed的native方法實現(xiàn), 閱讀hotspot中security.cpp代碼
#include <windows.h>
JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed
  (JNIEnv *env, jclass clazz, jint length, jbyteArray seed)
{
	//省略不關鍵代碼...
	else if (length > 0) {
            pbData = new BYTE[length];
            if (::CryptGenRandom(  // 此處通過調用windows提供的apiCryptGenRandom獲取隨機數(shù)
                hCryptProv,
                length,
                pbData) == FALSE) {
                ThrowException(env, PROVIDER_EXCEPTION, GetLastError());
                __leave;
            }
            result = env->NewByteArray(length);
            env->SetByteArrayRegion(result, 0, length, (jbyte*) pbData);
        }
  //省略不關鍵代碼...
}

沒有詳細研究CryptGenRandom的具體實現(xiàn)

4. 結論

4.1 推薦使用方式

  • 不推薦使用SecureRandom.getInstanceStrong()方式獲取SecureRandom(除非對隨機要求很高)
  • 推薦使用new SecureRandom()獲取SecureRandom, linux下從/dev/urandom讀取. 雖然是偽隨機, 但大部分場景下都滿足.

4.2 關于/dev/random的擴展

  • 由于/dev/random中的數(shù)據(jù)來自系統(tǒng)的擾動, 比如鍵盤輸入, 鼠標點擊, 等等, 當系統(tǒng)擾動很小時, 產生的隨機數(shù)不夠, 導致讀取/dev/random的進程會阻塞等待. 可以做個小實驗, 當阻塞時, 多點擊鼠標, 鍵盤輸入數(shù)據(jù)等操作, 會加速結束阻塞
  • 可以從通過這個命令cat /proc/sys/kernel/random/entropy_avail獲取當前系統(tǒng)的熵, 值越大, /dev/random中隨機數(shù)產生效率越高
  • 熵補償:可通過安裝linux下的工具haveged, 進行系統(tǒng)熵補償, 安裝后, 啟動haveged, 發(fā)現(xiàn)系統(tǒng)熵值從幾十增加到一千多, 此時在運行前面阻塞的程序(運行結果如下), 發(fā)現(xiàn)不再阻塞, 獲取100個隨機數(shù)只要29毫秒, 效率大大提升.

第91個隨機數(shù).
第92個隨機數(shù).
第93個隨機數(shù).
第94個隨機數(shù).
第95個隨機數(shù).
第96個隨機數(shù).
第97個隨機數(shù).
第98個隨機數(shù).
第99個隨機數(shù).
finish...time/ms:29

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • JAVA正則表達式的基本使用教程

    JAVA正則表達式的基本使用教程

    這篇文章主要給大家介紹了關于JAVA正則表達式的基本使用教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • spring AOP的After增強實現(xiàn)方法實例分析

    spring AOP的After增強實現(xiàn)方法實例分析

    這篇文章主要介紹了spring AOP的After增強實現(xiàn)方法,結合實例形式分析了spring面向切面AOP的After增強實現(xiàn)步驟與相關操作技巧,需要的朋友可以參考下
    2020-01-01
  • 打印Java程序的線程棧信息方式

    打印Java程序的線程棧信息方式

    這篇文章主要介紹了打印Java程序的線程棧信息方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring?Data?JPA系列JpaSpecificationExecutor用法詳解

    Spring?Data?JPA系列JpaSpecificationExecutor用法詳解

    這篇文章主要為大家介紹了Spring?Data?JPA系列JpaSpecificationExecutor用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • spring?security需求分析與基礎環(huán)境準備教程

    spring?security需求分析與基礎環(huán)境準備教程

    這篇文章主要為大家介紹了spring?security需求分析與基礎環(huán)境準備教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • Spring?MVC啟動之HandlerMapping作用及實現(xiàn)詳解

    Spring?MVC啟動之HandlerMapping作用及實現(xiàn)詳解

    這篇文章主要為大家介紹了Spring?MVC啟動之HandlerMapping作用及實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • SpringMVC結合Jcrop實現(xiàn)圖片裁剪

    SpringMVC結合Jcrop實現(xiàn)圖片裁剪

    這篇文章主要介紹了SpringMVC結合Jcrop實現(xiàn)圖片裁剪的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • SpringBoot如何統(tǒng)一清理數(shù)據(jù)

    SpringBoot如何統(tǒng)一清理數(shù)據(jù)

    這篇文章主要介紹了SpringBoot如何統(tǒng)一清理數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java?Autowired注解深入分析

    Java?Autowired注解深入分析

    @Autowired注解是Spring中非常重要且常見的,接下來就簡要的介紹一下它的用法。@Autowired默認是通過set方法,按照類型自動裝配JavaBean,set方法可省略不寫,它主要是修飾在成員變量上
    2023-01-01
  • Java使用excel工具類導出對象功能示例

    Java使用excel工具類導出對象功能示例

    這篇文章主要介紹了Java使用excel工具類導出對象功能,結合實例形式分析了java創(chuàng)建及導出Excel數(shù)據(jù)的具體步驟與相關操作技巧,需要的朋友可以參考下
    2017-10-10

最新評論

明水县| 乌兰浩特市| 漯河市| 林西县| 遵义市| 苗栗市| 东至县| 龙川县| 馆陶县| 鄂尔多斯市| 丹寨县| 嘉峪关市| 中牟县| 开阳县| 延川县| 沽源县| 长春市| 巴彦淖尔市| 龙南县| 渝中区| 扎囊县| 广汉市| 静海县| 贡觉县| 靖西县| 丹棱县| 永安市| 古交市| 长阳| 军事| SHOW| 江门市| 平陆县| 福海县| 皋兰县| 绍兴县| 靖边县| 扬中市| 临沧市| 辽中县| 钟祥市|