2013-07-09 21 views
16

パフォーマンス重視の環境でMessageDigestを使用して複数のスレッドから複数のキーをハッシュする必要があります。 MessageDigestはオブジェクトの状態を格納するため、MessageDigestはスレッドセーフではありません。キーのスレッドセーフハッシュを実現する最良の方法は何でしょうか?スレッドセーフなJavaでのMessageDigestが必要です

ユースケース:

MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); 

//somewhere later, just need to hash a key, nothing else 
messageDigest.update(key); 
byte[] bytes = messageDigest.digest(); 

具体的に:

  1. ウィルのThreadLocalは、動作が保証?パフォーマンスは ペナルティーですか?
  2. getInstanceによって返されるオブジェクトが異なり、 は互いに干渉しませんか?ドキュメントには '新しい' オブジェクトが記載されていますが、(共有) 共有コンクリートクラスの単なるラッパーかどうかわかりません。
  3. getInstance()が '実際の'新しいオブジェクトを返す場合、 ハッシュを計算するたびに新しいインスタンスを作成することをお勧めしますか?パフォーマンスペナルティの面では、どれくらいの費用がかかります ?

私の使用例は非常に単純です。単純なキーをハッシュするだけです。私は同期を使用する余裕がない。

おかげで、

答えて

27

は新しいMessageDigestインスタンスを使用すると、1つを必要とするたびに作成します。

getInstance()から返されたすべてのインスタンスが異なります。彼らは別々のダイジェストを維持しているので、それが必要です(そして、それがあなたのために十分でない場合は、here'sソースへのリンク)。

ThreadLocalは、スレッドプールとともに使用するとパフォーマンスが向上し、高価なオブジェクトを維持できます。 MessageDigestは、(特に、ソースを見て)構築するのに特に高価ではありません。

+1

私はcodeofのgetInstance()を参照した場合、それは新しいオブジェクトを作成していないようだ、むしろそれは私が下のテストケースを書いたオブジェクト オブジェクト[] OBJS = Security.getImpl を取得するために、セキュリティを呼び出します。 \t MessageDigest messageDigest1 = MessageDigest.getInstance( "SHA-1"); \t MessageDigest messageDigest2 = MessageDigest.getInstance( "SHA-1"); // を更新してダイジェストし、両方のmessageDigestオブジェクトが異なっており、その内側のオブジェクト/バッファも異なっていることがわかりました。だから、私はThreadLocalがうまくいくはずだと思います。 はい、スレッドプールを持つWebサーバーです。私はThreadLocalを使用します。 ありがとうございます。 –

+3

@AnilPadia - 私は強く**推奨していません**は 'ThreadLocal'を使用していません。早すぎる最適化です。私は新しい「MessageDigest」を作成するために約2 * micro *秒のマイクロベンチマークを書いた。これは、ダイジェストを使用するコードよりもはるかに上回ることになります。 – parsifal

+0

ThreadLocalを使用して見られる問題は何ですか?何百というスレッドがあっても、何百ものオブジェクトが存在します。私はそのようなオブジェクトのメモリフットプリントが本当に少ないことを発見しました。 ThreadLocalは私のためにうまくいきます。私もオブジェクトの作成をテストし、4マイクロ秒かかりました。私は本当になぜThreadLocalに反対しているのか知りたいです –

3

代わりに、MessageDigest用のApache CommonsのスレッドセーフラッパーDigestUtilsを使用してください。

sha1()は何が必要ありません:

byte[] bytes = sha1(key)

+0

下記の答えを見てください。 DigestUtils.getDigest()は単にMessageDigest.getInstance()を呼び出し、チェックされた例外をチェックされていない例外に変換するだけなので、DigestUtilsはMessageDigestよりスレッドセーフではありません。 – Siddhu

+1

ここでのポイントは、MessageDigestはスレッドセーフではないことです。そのため、同時実行環境で同じインスタンスを再利用すると、予測できない結果につながります。問題を解決するたびに新しい/異なるインスタンスを使用します(たとえばMessageDigest.getInstanceを呼び出すなど)。 DisgestUtilsは、各便利メソッドが新しいMessageDigestインスタンスを使用し、それぞれが(2回の呼び出しの後で)MessageDigest.getInstanceを呼び出して新しいインスタンスを作成するという意味でスレッドセーフです。たとえば、DigestUtilsを呼び出すたびに呼び出されます。 sha256Hex( "My string"); – Legna

1

がDigestUtilsもうスレッドセーフ生のMessageDigestよりもしていないようです。まだMessageDigest.getInstanceをカバーの下で使用しています。

+1

ここでのポイントは、MessageDigestはスレッドセーフではないことです。そのため、同時実行環境で同じインスタンスを再利用すると、予測できない結果につながります。 問題を解決するたびに新しい/異なるインスタンスを使用します(たとえばMessageDigest.getInstanceを呼び出すなど)。 DisgestUtilsは、各簡易メソッドが新しいMessageDigestインスタンスを使用し、それぞれが(2回の呼び出しの後で)MessageDigest.getInstanceを呼び出して新しいインスタンスを作成するという意味でスレッドセーフです。 たとえば、DigestUtilsへの各呼び出し。 sha256Hex( "My string"); MessageDigestの別のインスタンスを使用します – Legna

+0

説明をありがとう。 –

関連する問題