共享或不共享java加密服务提供程序 解决方案 MessageDigest=>根据需要经常创建新实例 KeyFactory=>使用单个共享实例 SecureRandom=>使用 密码=>使用 问题:
在编写安全性框架时,我面临着一个经常性的难题:“要共用还是不共用” 这个问题基本上分为两个“组”:共享或不共享java加密服务提供程序 解决方案 MessageDigest=>根据需要经常创建新实例 KeyFactory=>使用单个共享实例 SecureRandom=>使用 密码=>使用 问题:,java,pool,Java,Pool,在编写安全性框架时,我面临着一个经常性的难题:“要共用还是不共用” 这个问题基本上分为两个“组”: 第1组:SecureRandom,因为对nextBytes(…)的调用是同步的,它可能成为WebApp/多线程应用程序的瓶颈 第2组:加密服务提供商,如消息摘要,签名,密码,密钥工厂。。。(因为getInstance()?)的成本) 你的意见是什么 在这些问题上你有什么习惯 2013年7月9日编辑 最后我自己花时间测试了@QwerkyShareclass,结果非常。。。令人惊讶 这门课没有我最关心
SecureRandom
,因为对nextBytes(…)
的调用是同步的,它可能成为WebApp/多线程应用程序的瓶颈消息摘要
,签名
,密码
,密钥工厂
。。。(因为getInstance()
?)的成本)Share
class,结果非常。。。令人惊讶
这门课没有我最关心的:像游泳池或游泳池
因此,我重新编写了该类,以测试所有4个备选方案:
- 具有同步功能的单个共享实例
- 每个循环中都有新实例(我对可以将摘要创建拉到循环之外的情况不感兴趣)
- GenericObject池:
- StackObjectPool:
Thread.yield()
,以使负载具有更好的形状
结果(累积运行时):
- 消息摘要
- 新实例:420 s
- 单例:550秒
- StackObjectPool:800秒
- 通用对象池:1900秒
- 钥匙厂
- 新实例:400s
- 单例:350秒
- StackObjectPool:2900秒
- 通用对象池:3500秒
- 安全随机
- StackObjectPool:1600秒
- 新实例:2300 s
- GenericObject池:2300s
- 单实例:2800秒
- 密码
- StackObjectPool:2800秒
- 通用对象池:3500秒
- 单实例:5100 s
- 新实例:8000 s
对于MessageDigest和KeyFactory来说,池是性能杀手,甚至比具有同步瓶颈的单个实例更糟糕,但是当涉及到SecureRandom和Cipher时,它们确实很有用。此测试似乎有利于缓存
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);
long t0=System.currentTimeMillis();
字节[]字节=新字节[100];
MessageDigest md=MessageDigest.getInstance(“MD5”);
对于(int i=0;i<1000000;i++){
//MessageDigest md=MessageDigest.getInstance(“MD5”);
md.reset();
md.update(字节);
医学文摘();
}
System.out.println(System.currentTimeMillis()-t0);
当md在循环外时,打印579,在循环内时打印-953 如果您给100个线程访问共享的
MessageDigest
并让它们分别计算1000000个哈希,那么在我的机器上,第一个线程在70160ms内完成,最后一个线程在98748ms内完成
如果每次线程都创建一个新的MessageDigest
实例,那么第一个线程将在43392ms内完成,最后一个线程将在58691ms内完成
编辑:事实上,在这个示例中,只有两个线程,创建新实例的示例运行得更快
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();
}
}
import java.security.MessageDigest;
导入java.security.NoSuchAlgorithmException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
公开股{
最终字节[]字节=新字节[100];
最终消息摘要sharedDigest;
最终服务池;
int线程=100;
Share()抛出NoSuchAlgorithmException{
sharedDigest=MessageDigest.getInstance(“MD5”);
pool=Executors.newFixedThreadPool(线程);
}
void go(){
对于(int i=0;iReuse归结为昂贵的创建开销和同步访问开销之间的折衷。只有您可以选择,这取决于您的使用情况。请注意,这两个组之间没有区别,如果您在线程之间共享实例,您必须同步访问MessageDigest
等。当然@Qwerky有任何选择吗n需要线程/使用块之间的同步。问题是你如何在应用程序中处理这些类?这太好了——我希望这样的信息可以更容易地用于各种类。真的,我希望它在标准Javadoc中。所显示的是MessageDigest
有一个创建开销。在单线程情况下,重用总是更快。