是钥匙因线程安全



有一个服务类,需要从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似乎没有提及线程安全。

no,如果javadoc不提及线程,则不能保证线程安全性("同步"是实现细节&quot&quot&quot&quot&quot&quot。 [1] synchronized修饰符添加到您的generatePublicKey方法(或其他一些锁定形式(以使其成为线程安全,并确保添加Javadoc评论,指出应该是线程安全的。

另请参见:

  • 是否有标准注释应添加到该方法的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);
}

依次呼叫:

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
}

看起来班级确实在零件上锁定,而不是其他零件,这(我认为是出于目的,(意味着他们考虑了螺纹 - 萨夫蒂。这可能意味着他们原本打算安全地构造和使用工厂在多个线程上使用相同的算法,但这也不意味着。您需要详尽检查比赛条件的代码路径。

也就是说,请不要在Javadoc中的合同

中建立任何其他任何东西

no,如果要安全的线程,则必须使用同步块。

最新更新