2016-08-20 66 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(); 
}