2016-08-20 72 views
2

我写了自己的简体MessageDigest包装,现在我想知道它是否线程安全。此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); 
    } 
} 
+0

类似乎_immutable_,因此线程安全的。但是,这并不意味着该类的代码是线程安全的。 –

+0

好吧,如果'MessageDigest.digest'不是线程安全的,那么代码也不是。在Javadoc中没有提到线程安全性,所以最安全的假设是你的代码被破坏了。这只是一个假设,但是,必须检查 – Dici

+0

@MickMnemonic我认为我需要对新鲜副本进行摘要以保证安全。但是,如果克隆时发生了一些奇怪的事情呢?这不是真正的原子,我担心我需要一个锁的地方。 –

回答

2

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

例如,如果两个线程共享相同SimpleIMD对象和时间的方法调用的顺序会去是这样的:

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

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

事实上,在update()T1将具有错误的散列值之前,实际上,digest()甚至可能会重置潜在的MessageDigest实例。通过在全新副本上执行digest()可以解决此问题。

所以方法:

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

已改为:

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