I face a regular dilemna while coding security frameworks : "to pool or not to pool"
Basically this question is divided on two "groups" :
Group 1 : SecureRandom
because the call to nextBytes(...)
is synchronized and it could become a bottleneck for a WebApp / a multi-threaded app
Group 2 : Crypto service providers like MessageDigest
, Signature
, Cipher
, KeyFactory
, ... (because of the cost of the getInstance()
?)
What is your opinion ?
What are you habits on such questions?
I finally took time to test @Qwerky Share
class by myself and I find the result quite ... surprising.
The class was lacking my main concern : Pools like GenericObjectPool or StackObjectPool.
So I've reworked the class to test all 4 alternatives :
I had to lower the number of loops to 100000 since 1M was taking too much time with pools.
I also added a Thread.yield()
at the end of each loop to give the load a nicer shape.
Results (cummulative runtime):
For MessageDigest and KeyFactory, pools are perf killers and are even worse than a single instance with a synchronisation bottleneck, whereas they are really usefull when it comes to SecureRandom and Cipher
If you give 100 threads access to a shared MessageDigest
and get them to calculate 1,000,000 hashes each then on my machine the first thread finishes in 70,160ms and the last finishes in 98,748ms.
If the threads create a new instance of MessageDigest
each time, then the first thread finishes in 43,392ms and the last 58,691ms.
Edit:
In fact with this example, with only two threads the example creating new instances runs quicker.
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With