KeyFactory是线程安全的吗? [英] Is KeyFactory thread-safe?

查看:295
本文介绍了KeyFactory是线程安全的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个服务类,需要从X.509编码的公钥表示形式生成PublicKey实例.此类的一个实例将服务多个线程.这样做是正确的吗?

There is a service class that needs to generate PublicKey instances from X.509-encoded public key representations. One instance of this class will service multiple threads. Is it correct to do something like this?

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()方法可以由不同的线程同时调用.

I.e. is the KeyFactory instance used here is thread-safe? generatePublicKey() method may be called by different threads concurrently.

Javadocs似乎没有提到线程安全性.

Javadocs don't seem to mention thread-safety.

推荐答案

否,如果

No, if the Javadoc makes no mention of thread-saftey then thread safety is not guaranteed ("synchronization is an implementation detail").[1] Add a synchronized modifier to your generatePublicKey method (or some other form of locking) to make it thread-safe and be sure to add a Javadoc comment noting that it is supposed to be thread-safe.

另请参阅:

  • Is there a standard annotation which should be added to the method's Javadoc to denote that a method should be called on a particular thread?
  • Characterizing thread safety (emphasis mine)

您查看过Javadoc一类多少次,并且想知道该类是线程安全的吗?" 在没有清晰文档的情况下,读者可能会对类的线程安全性做出错误的假设.也许他们只是假设它不是线程安全的(那真的很糟糕!),或者他们假设可以通过在调用其方法之一之前在对象上进行同步来使其成为线程安全的. (这可能是正确的,或者可能只是效率低下,或者在最坏的情况下,只能提供线程安全性的错觉).无论如何,最好在文档中明确说明跨线程共享实例时类的行为.

How many times have you looked at the Javadoc for a class, and wondered, "Is this class thread-safe?" In the absence of clear documentation, readers may make bad assumptions about a class's thread safety. Perhaps they'll just assume it is thread-safe when it's not (that's really bad!), or maybe they'll assume that it can be made thread-safe by synchronizing on the object before calling one of its methods (which may be correct, or may simply be inefficient, or in the worst case, could provide only the illusion of thread safety). In any case, it's better to be clear in the documentation about how a class behaves when an instance is shared across threads.

[...]

类的线程安全行为是其规范的内在部分,应作为其文档的一部分.因为还没有描述性的方法来描述类的线程安全行为(尚未),所以必须以文本形式进行描述.尽管Bloch的用于描述类的线程安全程度的五层系统无法涵盖所有​​可能的情况,但这是一个很好的开始.当然,如果每个类的Javadoc中都包含这种程度的线程行为,我们会更好.

A class's thread-safety behavior is an intrinsic part of its specification, and should be part of its documentation. Because there is no declarative way of describing a class's thread-safety behavior (yet), it must be described textually. While Bloch's five-tier system for describing a class's degree of thread safety does not cover all possible cases, it's a very good start. Certainly we'd all be better off if every class included this degree of threading behavior in its Javadoc.

看起来您可能会使用它(也就是说,正如亨特在注释中指出的那样,一旦拥有一个KeyFactory实例,从多个线程中调用KeyFactory#generatePublic可能是安全的).

It looks like your use might be (that is, as hunter pointed out in the comments, once you have a KeyFactory instance, it might be safe to call KeyFactory#generatePublic from multiple threads).

一些源代码潜水,KeyFactory.getInstance(String)看起来像这样:

A bit of source diving, KeyFactory.getInstance(String) looks something like so:[2] [3]

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看起来像这样:

public final PublicKey generatePublic(KeySpec keySpec)
        throws InvalidKeySpecException {
    if (serviceIterator == null) {
        return spi.engineGeneratePublic(keySpec);
    }
    // Truncated for brevity
}

看起来类确实在某些部分中进行了锁定,而没有进行其他锁定,(我想这是有目的的,这意味着它们考虑了线程安全性).这可能意味着他们原本打算安全地在多个线程上为同一算法构造和使用工厂,但这可能并不意味着这样做.您需要彻底检查代码路径中的竞争条件.

It does look like the class does some locking in parts and not others, which (I imagine was for a purpose and) means that they took thread-saftey into consideration. It could mean that they had intended for it to be safe to construct and use a factory for the same algorithm on multiple threads but it might also not mean that. You would need to exhaustively check the code paths for race conditions.

也就是说,除了Javadoc中的合同外,请不要在没有合同的情况下构建任何东西.

That said, please don't build anything assuming a contract other than what's in the Javadoc.

这篇关于KeyFactory是线程安全的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆