Rom*_*kiy 5 java multithreading public-key-encryption
有一个服务类需要PublicKey从X.509编码的公钥表示形式生成实例。此类的一个实例将服务多个线程。这样做是正确的吗?
public class MyService {
private final KeyFactory rsaKeyFactory;
public MyService() throws NoSuchAlgorithmException {
rsaKeyFactory = KeyFactory.getInstance("RSA");
}
public PublicKey generatePublicKey(byte[] publicKeyBytes) throws GeneralSecurityException {
return rsaKeyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
}
}
Run Code Online (Sandbox Code Playgroud)
即KeyFactory这里使用的实例是线程安全的吗?generatePublicKey()方法可以由不同的线程同时调用。
Javadocs似乎没有提到线程安全性。
不,如果Javadoc没有提到线程安全,则不能保证线程安全(“同步是一个实现细节”)。[1]synchronized为您的generatePublicKey方法(或某种其他形式的锁定)添加一个修饰符以使其成为线程安全的,并确保添加一个 Javadoc 注释,指出它应该是线程安全的。
也可以看看:
表征线程安全(强调我的)
您有多少次查看 Javadoc 中的某个类,并想知道“这个类是否线程安全?” 如果没有明确的文档,读者可能会对类的线程安全性做出错误的假设。也许他们只是假设它不是线程安全的(这真的很糟糕!),或者他们可能会假设它可以通过在调用其方法之一之前同步对象来使其成为线程安全的(这可能是正确,或者可能只是效率低下,或者在最坏的情况下,只能提供线程安全的错觉)。无论如何,最好在文档中明确说明跨线程共享实例时类的行为方式。
[...]
类的线程安全行为是其规范的固有部分,应该是其文档的一部分。因为(目前)还没有描述类的线程安全行为的声明性方式,所以必须用文本来描述。虽然 Bloch 用于描述类的线程安全程度的五层系统并未涵盖所有可能的情况,但这是一个非常好的开始。当然,如果每个类都在其 Javadoc 中包含这种程度的线程行为,我们都会过得更好。
看起来您的用途可能是(也就是说,正如 Hunter 在评论中指出的那样,一旦您拥有一个KeyFactory实例,KeyFactory#generatePublic从多个线程调用可能是安全的)。
有点源码潜水,KeyFactory.getInstance(String)看起来像这样:[2] [3]
public static KeyFactory getInstance(String algorithm)
throws NoSuchAlgorithmException {
return new KeyFactory(algorithm);
}
Run Code Online (Sandbox Code Playgroud)
依次调用:
private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
this.algorithm = algorithm;
List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
serviceIterator = list.iterator();
// fetch and instantiate initial spi
if (nextSpi(null) == null) {
throw new NoSuchAlgorithmException
(algorithm + " KeyFactory not available");
}
}
Run Code Online (Sandbox Code Playgroud)
而nextSpi看起来像:
private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
synchronized (lock) {
// Truncated for brevity
}
}
Run Code Online (Sandbox Code Playgroud)
而且KeyFactory#generatePublic看起来就像这样:
public final PublicKey generatePublic(KeySpec keySpec)
throws InvalidKeySpecException {
if (serviceIterator == null) {
return spi.engineGeneratePublic(keySpec);
}
// Truncated for brevity
}
Run Code Online (Sandbox Code Playgroud)
看起来这个类确实做了一些部分锁定而不是其他部分,这(我想是出于某种目的)意味着他们考虑了线程安全性。这可能意味着他们打算在多个线程上为相同的算法构建和使用工厂是安全的,但这也可能不是那个意思。您需要彻底检查竞争条件的代码路径。
也就是说,除了 Javadoc 中的内容之外,请不要构建任何假设合同的内容。
| 归档时间: |
|
| 查看次数: |
839 次 |
| 最近记录: |