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

Cer*_*ber 10 java pool

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

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

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

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

  2. 第2组:加密服务提供商,如MessageDigest,Signature,Cipher,KeyFactory,...(因为的成本getInstance()?)

你有什么意见 ?

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

编辑09/07/2013

我终于花时间自己测试了@Qwerky Share课程,我觉得结果很......令人惊讶.

这个类缺乏我的主要关注:像GenericObjectPoolStackObjectPool这样的池.

所以我重新修改了这个类以测试所有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方面非常有用

Qwe*_*rky 6

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

如果线程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<threads; i++) {
      pool.execute(new Runnable() {
        public void run() {
          long start = System.currentTimeMillis();
          for (int i=0; i<1000000; i++) {
            /*
            synchronized (sharedDigest) {
              sharedDigest.reset();
              sharedDigest.update(bytes);
              sharedDigest.digest();
            }*/
            try {
              MessageDigest digest = MessageDigest.getInstance("MD5");
              digest.reset();
              digest.update(bytes);
              digest.digest();
            } catch (Exception ex) {
              ex.printStackTrace();
            }
          }
          long end = System.currentTimeMillis();
          System.out.println(end-start);
          pool.shutdown();
        }
      });
    }

  }

  public static void main(String[] args) throws Exception {
    Share share = new Share();
    share.go();
  }

}
Run Code Online (Sandbox Code Playgroud)