2013-07-09 64 views
16

我需要在性能严重的环境中使用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()返回'real'新对象, 是否建议每次创建新实例需要 计算散列?在性能方面的惩罚 - 如何代价是 呢?

我的用例非常简单 - 只需散列一个简单的键。我无法使用同步。

感谢,

回答

27

创建一个新的MessageDigest实例每次需要时间。

getInstance()返回的所有实例都是不同的。他们需要,因为他们维护单独的摘要(如果这还不够,here's链接到源)。

ThreadLocal可以与线程池一起使用时可以提供性能优势,以维护昂贵的构造对象。 MessageDigest构建起来并不是特别昂贵(再看一下源代码)。

+1

如果我看到codeof的getInstance(),它似乎并没有创建新的对象,而是调用安全来获取对象 对象[] = OBJ文件Security.getImpl 我写了下面的测试案例: \t MessageDigest messageDigest1 = MessageDigest.getInstance(“SHA-1”); \t MessageDigest messageDigest2 = MessageDigest.getInstance(“SHA-1”); //更新和摘要 并看到messageDigest对象不同,以及它们的内部对象/缓冲区也不同。所以,我想ThreadLocal应该工作。 是的,它是一个带有线程池的Web服务器。我将使用ThreadLocal。 谢谢, –

+3

@AnilPadia - 我**强**建议**不**使用'ThreadLocal'。这是过早的优化。我编写了一个微型基准测试,耗时约2 * micro * -s,创建一个新的MessageDigest。这将远远超过使用摘要的代码。 – parsifal

+0

使用ThreadLocal时看到的问题是什么?即使我有数百个线程,也会有数百个这样的对象。我发现这些对象的内存占用真的很少。 ThreadLocal对我来说工作正常。我还测试了创建对象,并花了4微秒。我真的想知道为什么反对ThreadLocal –

3

作为替代方案,使用,Apache Commons的MessageDigest的线程安全包装器。

sha1()做你所需要的:

byte[] bytes = sha1(key)

+0

请参阅下面的答案;因为DigestUtils.getDigest()只是调用MessageDigest.getInstance()并将检查的异常转换为未经检查的异常,所以DigestUtils不再是MessageDigest的线程安全。 – Siddhu

+1

这里的要点是MessageDigest不是线程安全的,因此在并发环境中重复使用同一个实例会导致不可预知的结果。使用新的/不同的实例(例如通过调用MessageDigest.getInstance)每次解决您的问题。 DisgestUtils是线程安全的,它的每个便捷方法都使用一个新的MessageDigest实例,每个实例都调用MessageDigest.getInstance创建一个新实例。例如每次调用DigestUtils。 sha256Hex(“My string”);将使用MessageDigest的另一个实例 – Legna

1

DigestUtils似乎没有再被线程不是原始消息摘要。仍然使用封面下的MessageDigest.getInstance。

+1

此处的要点是MessageDigest不是线程安全的,因此在并发环境中重复使用同一实例会导致不可预知的结果。 每次解决您的问题时都会使用新的/不同的实例(例如通过调用MessageDigest.getInstance)。 DisgestUtils是线程安全的,它的每个便捷方法都使用一个新的MessageDigest实例,每个实例都调用MessageDigest.getInstance(创建一个新实例)。例如,每次调用DigestUtils时都会调用这个函数。 sha256Hex(“My string”);将使用不同的MessageDigest实例 – Legna

+0

感谢您的澄清。 –