有一个服务类需要从X.509编码的公钥表示中生成PublicKey
个实例。此类的一个实例将为多个线程提供服务。做这样的事情是对的吗?
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));
}
}
即。这里使用的KeyFactory
实例是线程安全的吗? generatePublicKey()
方法可以由不同的线程同时调用。
Javadocs似乎并没有提到线程安全性。
答案 0 :(得分:4)
不,如果the Javadoc未提及thread-saftey,则无法保证线程安全(“同步是实现细节”)。 [1] 添加{{ 1}}修饰符到你的synchronized
方法(或其他形式的锁定),使其成为线程安全的,并确保添加一个Javadoc注释,注意它应该是线程安全的。
另见:
Characterizing thread safety(强调我的)
你有多少次看过一个类的Javadoc,并想知道,“这个类是否是线程安全的?” 如果没有明确的文档,读者可能会对类的线程安全做出错误的假设。也许他们只是假设它不是线程安全的(那真的很糟糕!),或者他们可能会假设它可以通过在调用其方法之前同步对象来使其成为线程安全的(这可能是正确的,或者可能只是效率低下,或者在最坏的情况下,只能提供线程安全的错觉)。在任何情况下,最好在文档中清楚说明当跨线程共享实例时类的行为。
[...]
类的线程安全行为是其规范的固有部分,应该是其文档的一部分。因为没有描述类的线程安全行为的声明方式(尚未),所以必须以文本方式进行描述。虽然布洛赫用于描述一个级别的线程安全程度的五层系统并未涵盖所有可能的情况,但这是一个非常好的开始。当然如果每个类在其Javadoc中包含这种程度的线程行为,我们都会变得更好。
看起来你的用途可能就是(就像猎人在评论中指出的那样,一旦你有generatePublicKey
个实例,从多个线程调用KeyFactory
可能是安全的。 / p>
一些潜水源潜水,KeyFactory#generatePublic
看起来像这样: [2] [3]
KeyFactory.getInstance(String)
反过来说:
public static KeyFactory getInstance(String algorithm)
throws NoSuchAlgorithmException {
return new KeyFactory(algorithm);
}
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");
}
}
看起来像:
nextSpi
private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
synchronized (lock) {
// Truncated for brevity
}
}
看起来像是这样:
KeyFactory#generatePublic
看起来这个类看起来有些锁定部分而不是其他部分,这些(我想是出于某种目的而言)意味着它们考虑了线程安全性。这可能意味着他们打算在多线程上构建和使用相同算法的工厂是安全的,但它也可能并不意味着。您需要详尽检查竞争条件的代码路径。
那就是说,请假设除了Javadoc 之外的合同,请不要构建任何东西。
答案 1 :(得分:0)
不,如果您想要线程安全,则必须使用同步块。