要汇集还是不汇集java加密服务提供商

  • MessageDigest =>根据需要经常创建新实例
  • KeyFactory =>使用单个共享实例
  • SecureRandom =>使用StackObjectPool
  • Cipher =>使用StackObjectPool

在编写安全框架时,我面临着一个常规的困境:“汇集或不汇集”

基本上这个问题分为两个“群体”:

  1. 第1组: SecureRandom因为对nextBytes(...)的调用是同步的,它可能成为WebApp /multithreading应用程序的瓶颈

  2. 第2组:加密服务提供商,如MessageDigestSignatureCipherKeyFactory ,……(因为getInstance()的成本?)

你有什么意见 ?

你在这些问题上的习惯是什么?

编辑09/07/2013

我终于抽出时间亲自测试@Qwerky Share课程,我发现结果非常……令人惊讶。

这个类缺乏我的主要关注:像GenericObjectPool或StackObjectPool这样的池。

所以我重新修改了这个类以测试所有4种选择:

  • 具有同步gist的单个共享实例
  • 每个循环中的新实例(当你可以在循环外拉动摘要时,我对这种情况不感兴趣)
  • GenericObjectPool: 要点
  • StackObjectPool: 要点

我不得不将循环次数降低到100000,因为1M花费了太多时间来使用池。

我还在每个循环的末尾添加了一个Thread.yield() ,以便为负载提供更好的形状。

结果(累积运行时):

  • 信息摘要
    • 新实例:420秒
    • 单个实例:550秒
    • StackObjectPool:800秒
    • GenericObjectPool:1900年代
  • 的KeyFactory
    • 新实例:400s
    • 单个实例:350秒
    • StackObjectPool:2900秒
    • GenericObjectPool:3500秒
  • 的SecureRandom
    • StackObjectPool:1600秒
    • 新实例:2300秒
    • GenericObjectPool:2300s
    • 单个实例:2800秒
  • 暗号
    • StackObjectPool:2800秒
    • GenericObjectPool:3500秒
    • 单个实例:5100秒
    • 新实例:8000秒

结论

对于MessageDigest和KeyFactory,池是执行器杀手,甚至比具有同步瓶颈的单个实例更糟糕,而它们在SecureRandom和Cipher方面非常有用

如果您给100个线程访问共享的MessageDigest并让它们计算1,000,000个哈希,那么在我的机器上第一个线程在70,160ms完成,最后一个在98,748ms完成。

如果线程每次都创建一个MessageDigest的新实例,那么第一个线程将在43,492ms完成,最后一个58,691ms完成。

编辑:
事实上,在这个例子中,只有两个线程,创建新实例的示例运行得更快。

 import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Share { final byte[] bytes = new byte[100]; final MessageDigest sharedDigest; final ExecutorService pool; int threads = 100; Share() throws NoSuchAlgorithmException { sharedDigest = MessageDigest.getInstance("MD5"); pool = Executors.newFixedThreadPool(threads); } void go() { for (int i=0; i 

这个测试似乎有利于缓存

 long t0 = System.currentTimeMillis(); byte[] bytes = new byte[100]; MessageDigest md = MessageDigest.getInstance("MD5"); for(int i = 0; i < 1000000; i++) { //MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(bytes); md.digest(); } System.out.println(System.currentTimeMillis() - t0); 

当md在循环之外时,它打印579,当在内部 - 953。