解决方案
问题
在对安全性框架进行编码时,我经常遇到两难的问题:“要合并还是不合并”
基本上,这个问题分为两个“组”:
SecureRandom
,因为对nextBytes(...)
的调用已同步,并且可能成为WebApp/多线程应用程序MessageDigest
,Signature
,Cipher
,KeyFactory
,...(由于getInstance()
的成本?)你有什么意见 ?
您对这些问题有什么习惯?
编辑09/07/2013
我终于花了一些时间独自测试@Qwerky
Share
类,我发现结果相当……令人惊讶。上课时我最担心的是:GenericObjectPool或StackObjectPool之类的池。
因此,我对类(class)进行了重新设计,以测试所有4种选择:
由于1M在池中花费了太多时间,因此我不得不将循环数降低到100000。
我还在每个循环的末尾添加了
Thread.yield()
,以使负载更美观。结果(累计运行时间):
结论
对于MessageDigest和KeyFactory,池是性能的杀手,甚至比具有同步瓶颈的单个实例还要差,而对于SecureRandom和Cipher来说,它们确实非常有用
最佳答案
如果让100个线程访问共享的MessageDigest
,并让它们分别计算1,000,000个哈希,则在我的计算机上,第一个线程在70,160ms内完成,最后一个线程在98,748ms内完成。
如果线程每次都创建一个新的MessageDigest
实例,那么第一个线程将在43,392ms内结束,最后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();
}
}