【问题标题】:Is this MessageDigest wrapper thread-safe?这个 MessageDigest 包装器是线程安全的吗?
【发布时间】:2016-08-20 00:12:13
【问题描述】:

我编写了自己的简化 MessageDigest 包装器,现在我想知道它是否是线程安全的。

public final class SimpleIMD implements ImmutableMessageDigest {
    private final MessageDigest md;

    public SimpleIMD(MessageDigest md) {
        this.md = this.cloneMessageDigest(md);
    }

    private MessageDigest cloneMessageDigest(MessageDigest original) {
        MessageDigest clone = null;
        try {
            clone = (MessageDigest) original.clone();
        } catch (CloneNotSupportedException cnse) {
            throw new RuntimeException(
                "Failed to instantiate a new SimpleImd instance.",
                cnse
            );
        } finally {
            return clone;
        }
    }

    @Override
    public byte[] digest() {
        return this.md.digest();
    }

    @Override
    public ImmutableMessageDigest update(byte[] arr, int offset, int len) {
        MessageDigest newMsgDigest = this.cloneMessageDigest(this.md);
        newMsgDigest.update(arr, offset, len);
        return new SimpleIMD(newMsgDigest);
    }
}

【问题讨论】:

  • 该类似乎是不可变的,因此是线程安全的。然而,这并不意味着代码使用这个类是线程安全的。
  • 好吧,如果MessageDigest.digest 不是线程安全的,那么代码也不是。 Javadoc 中没有提到线程安全,因此最安全的假设是您的代码已损坏。然而,这只是一个假设,必须进行检查
  • @MickMnemonic 我认为为了安全起见,我需要对新副本执行摘要。但是……如果克隆时发生了奇怪的事情怎么办?它不是真正的原子,我担心我需要在某个地方加锁。
  • @Dici 不,MessageDigest 不是线程安全的。
  • @JanezKuhar,您传递给代码中elsewhere的构造函数的MessageDigest 是怎样的?我认为您的线程安全问题仅取决于该问题。

标签: java concurrency thread-safety immutability


【解决方案1】:

正如我所怀疑的,我的代码不是线程安全的。

例如,如果 2 个线程共享同一个 SimpleIMD 对象,那么方法调用的时间顺序将是这样的:

  T1                 T2
  |                  |
update()             |
  |                  |
  |                digest()
  |                  |
  |                  |
  |                  |

那么不能保证update() 会在digest() 之前完成。

事实上,digest() 甚至可能在update()T1 之前重置底层的MessageDigest 实例,并且T1 会有错误的哈希值。这个问题可以通过在新副本上执行digest() 来解决。

所以方法:

@Override
public byte[] digest() {
    return this.md.digest();
}

必须改为:

@Override
public byte[] digest() {
    return this.cloneMessageDigest(this.md).digest();
}

更新

此处介绍的解决方案已合并到 ImmutableMessageDigest 中,这是我编写的开源库 Caesar 的一部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多