这个 MessageDigest 包装器线程安全吗?
Is this MessageDigest wrapper thread-safe?
我编写了自己的简化 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);
}
}
如我所料,我的代码不是线程安全的。
例如,如果 2 个线程共享同一个 SimpleIMD
对象,并且方法调用的时间顺序将如下所示:
T1 T2
| |
update() |
| |
| digest()
| |
| |
| |
那么不能保证 update()
会在 digest()
之前完成。
事实上,digest()
甚至可能在 update()
之前重置基础 MessageDigest
实例,并且 T1
将具有错误的哈希值。这个问题可以通过对新副本执行 digest()
来解决。
所以方法:
@Override
public byte[] digest() {
return this.md.digest();
}
必须更改为:
@Override
public byte[] digest() {
return this.cloneMessageDigest(this.md).digest();
}
更新
此处介绍的解决方案已纳入我编写的开源库 ImmutableMessageDigest
that's part of Caesar。
我编写了自己的简化 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);
}
}
如我所料,我的代码不是线程安全的。
例如,如果 2 个线程共享同一个 SimpleIMD
对象,并且方法调用的时间顺序将如下所示:
T1 T2
| |
update() |
| |
| digest()
| |
| |
| |
那么不能保证 update()
会在 digest()
之前完成。
事实上,digest()
甚至可能在 update()
之前重置基础 MessageDigest
实例,并且 T1
将具有错误的哈希值。这个问题可以通过对新副本执行 digest()
来解决。
所以方法:
@Override
public byte[] digest() {
return this.md.digest();
}
必须更改为:
@Override
public byte[] digest() {
return this.cloneMessageDigest(this.md).digest();
}
更新
此处介绍的解决方案已纳入我编写的开源库 ImmutableMessageDigest
that's part of Caesar。