Java MessageDigest.getInstance返回的实例非线程安全

问题

在当前的性能管理系统中,系统会通过Java自带的MD5 Digest为性能指标生成一个固定的列名。
但是在测试的过程中,总是会发现有些指标生成列名失败,或者列名相同。

定位及原因

生成列名代码大概如下

    private static volatile MessageDigest md5MessageDigest = null;
    
    public static String getField(String value) throws NoSuchAlgorithmException {
        if (md5MessageDigest == null) {
            md5MessageDigest = MessageDigest.getInstance("MD5");
        }
        
        byte[] digestBytes = md5MessageDigest.digest(value.getBytes(StandardCharsets.UTF_8));
        
        return toField(digestBytes);
    }
    
    public static String toField(byte[] digestBytes) {
        // 实际生成比下面的复杂,仅为了演示。
        return "ind_" + String(digestBytes, StandardCharsets.UTF_8);
    }

MessageDigest对应的MD5 Digest实例包含了个多个非静态变量,不加锁时使用同个MD5 Digest会出现多线程问题。
系统的性能指标一般是通过Excel一次性导入,导入是并发的,所以会引发上面的问题。

解决方法

每次使用MessageDigest.getInstance获取唯一的MD5 Digest。

    public static String getField(String value) throws NoSuchAlgorithmException {
        MessageDigest md5MessageDigest = MessageDigest.getInstance("MD5");

        byte[] digestBytes = md5MessageDigest.digest(value.getBytes(StandardCharsets.UTF_8));

        return toField(digestBytes);
    }

    public static String toField(byte[] digestBytes) {
        // 实际生成比下面的复杂,仅为了演示。
        return "ind_" + String(digestBytes, StandardCharsets.UTF_8);
    }

你可能感兴趣的:(Java MessageDigest.getInstance返回的实例非线程安全)