I'm running into an issue where multiple threads are fighting over an RSA javax.crypto.Cipher
, and I'm looking into keeping a collection of Ciphers - one for each thread. However Cipher.getInstance()
gives me the same instance. Should I look into a clone()
or is there a better way, like a new Cipher()
?
We've considered synchronized{}
and just use single instance of Cipher
but it's too slow.
Thanks for all the help in advance!
-
1That should not happen. `Cipher` should create an instance of `CipherSpi` each time `getInstance()` is called. Are you using a specific cryptographic provider? – Maarten Bodewes Aug 13 '12 at 21:52
-
Related to https://stackoverflow.com/questions/13913075/to-pool-or-not-to-pool-java-crypto-service-providers – Gray Nov 02 '22 at 20:40
1 Answers
It looks to me that different threads get different Cipher
instances -- at least under JDK 1.6.0_33 under Mac OSX. Maybe this is because I'm using BouncyCastle provider?
Were you trying to call getInstance()
from the same thread twice or from different threads? clone()
does not seem to be available for Ciphers so that is not an option.
One solution would be to use object pools so that multiple cipher instances would be used in parallel by multiple threads. This might not work if the the JDK returns the same cipher instance on the same thread instead of a new instance.
The following code seems to spit out different identity hashcode objects for me at least:
private static final ThreadLocal<Cipher> localDigest = new ThreadLocal<Cipher>(){
@Override
protected Cipher initialValue() {
try {
return Cipher.getInstance("RSA");
} catch (Exception e) {
// ugly but necessary
throw new RuntimeException(e);
}
}
};
public static void main(String[] args) {
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();
}
private static class MyRunnable implements Runnable {
@Override
public void run() {
Cipher cipher = localDigest.get();
System.out.println("Got digest " + System.identityHashCode(cipher));
...
}
}
As pointed out by @marius_neo in the comments, ThreadLocal
s can cause memory leaks in certain situations. See: To Pool or not to Pool java crypto service providers

- 115,027
- 24
- 293
- 354
-
1A provider can always mess up the underlying implementation of course. If they map to the same `CipherSpi` instance you would get in trouble. I've never experienced that myself, but it certainly can happen (I've implemented thread safe providers). – Maarten Bodewes Aug 13 '12 at 21:54
-
Cool... Maybe ThreadLocal is enough in this case, implementing this now. Thanks! – BZapper Aug 13 '12 at 21:58
-
1Note that using ThreadLocal variables within webapplications for sharing cipher instances will lead to memory leaks : https://plumbr.eu/blog/how-to-shoot-yourself-in-foot-with-threadlocals Avoid this by doing object pools instead : http://stackoverflow.com/questions/13913075/to-pool-or-not-to-pool-java-crypto-service-providers – marius_neo Jun 13 '14 at 09:36
-
Could you elaborate more on cryptographic providers. I am getting false for `System.out.println("Equals : " + Cipher.getInstance("DES/CBC/PKCS5Padding").equals(Cipher.getInstance("DES/CBC/PKCS5Padding")));` – Aniket Thakur Dec 30 '15 at 07:34
-
1
-
1new link for resource in @marius_neo 's comment: https://plumbr.io/blog/locked-threads/how-to-shoot-yourself-in-foot-with-threadlocals – o_O Nov 02 '22 at 06:49