4

MessageDigest的并发问题

 2 years ago
source link: https://www.wencst.com/archives/2140
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

MessageDigest的并发问题

作者: wencst 分类: JAVA,程序设计 发布时间: 2021-08-24 11:38 阅读: 34 次

在程序中采用了静态变量的方式实例化了MessageDigest

    private static MessageDigest CRYPT = null;

    static {
        try {
            CRYPT = MessageDigest.getInstance("SHA-1");
        } catch (NoSuchAlgorithmException e) {
            log.warn("Failed to get sha-1 message digest.");
        }
    }

然后采用SHA1进行加密

    private String encryptSHA1(String key) {
        String sha1 = "";
        CRYPT.reset();
        //1
        CRYPT.update((key + SALT).getBytes(StandardCharsets.UTF_8));
        //2         sha1 = byteToHex(CRYPT.digest());
        return sha1; 
    }

SALT目前是固定值,当调用encryptSHA1时,偶尔会返回错误的加密值。

首先,SHA1的加密方式是每次加密结果都一致。所以猜测是并发引起的。下面实验验证一下。

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            System.out.println(service.encryptSHA1("12345678"));
            System.out.println(service.encryptSHA1("87654321"));
            Thread.sleep(100);
        }
    }

结果没有问题。

    public static void main(String[] args) {
        Thread[] ts = new Thread[100];
        for (int i = 0;i<100;i++) {
            Thread t = new Thread(String.valueOf(new Random().nextLong())) {
                public void run() {
                    service.encryptSHA1(Thread.currentThread().getName());
                }
            };
            ts[i] = t;
        }
        for (int i = 0;i<100;i++) {
            Thread t = ts[i];
            t.start();
        }
    }

这个结果出问题了,当并发的时候,加密的结果偶尔是上一个加密的结果。

    private String encryptSHA1(String key) {
        String sha1 = byteToHex(DigestUtils.sha1((key + SALT).getBytes(StandardCharsets.UTF_8)));
        return sha1;
    }

再次使用实验二中的main方法验证,结果正常。

    private String encryptSHA1(String key) {
        String sha1 = "";
        CRYPT.reset();
        //1
        CRYPT.update((key + SALT).getBytes(StandardCharsets.UTF_8));
        //2
        sha1 = byteToHex(CRYPT.digest());
        return sha1;
    }

由于CRYPT是静态变量,只初始化一次,所以多个线程使用的是同一个对象,当并发比较大时,会出现A线程执行完//1还没有执行//2时,B线程执行完//1,此时A线程执行//2,会显示B线程的结果。

而DigestUtils实际使用的是每次调用 crypt = MessageDigest.getInstance(“SHA-1”); 验证每次生成的crypt都是新的对象。

因此我们也可以自己实现DigestUtils的sha1方法。

如果文章对您有用,扫一下支付宝的红包,不胜感激!

欢迎加入QQ群进行技术交流:656897351(各种技术、招聘、兼职、培训欢迎加入)

Leave a Reply Cancel reply

You must be logged in to post a comment.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK