Безопасно ли защищать поток SecureRandom?
Является SecureRandom
поток безопасно? То есть, после его инициализации можно ли рассчитывать на доступ к следующему случайному числу, чтобы обеспечить безопасность потока? Изучение исходного кода, кажется, показывает, что это так, и этот отчет об ошибке, кажется, указывает на то, что отсутствие документации в качестве поточно-ориентированной является проблемой javadoc. Кто-нибудь подтвердил, что это на самом деле потокобезопасно?
4 ответа
Да, это. Расширяется Random
, которая всегда имела де-факто реализацию потоковой безопасности, и, начиная с Java 7, явно гарантирует безопасность потоков.
Если много потоков используют один SecureRandom
, может быть раздор, который вредит производительности. С другой стороны, инициализация SecureRandom
экземпляр может быть относительно медленным. Будет ли лучше разделить глобальный ГСЧ или создать новый для каждого потока, будет зависеть от вашего приложения. ThreadLocalRandom
класс может быть использован в качестве шаблона, чтобы обеспечить решение, которое поддерживает SecureRandom
,
Текущая реализация SecureRandom
является потокобезопасным, в частности, два метода мутации nextBytes(bytes[])
а также setSeed(byte[])
синхронизированы.
Ну, насколько я могу судить, все методы мутации в конечном итоге направляются через эти два метода, и SecureRandom
переопределяет несколько методов в Random
чтобы обеспечить это. Что работает, но может быть хрупким, если реализация будет изменена в будущем.
Лучшее решение - вручную синхронизировать на SecureRandom
экземпляр первый. Это означает, что каждый стек вызовов получает две блокировки для одного и того же объекта, но это обычно очень дешево на современных JVM. То есть нет особого вреда в явной синхронизации себя. Например:
SecureRandom rnd = ...;
byte[] b = new byte[NRANDOM_BYTES];
synchronized (rnd) {
rnd.nextBytes(b);
}
См. https://bugs.openjdk.java.net/browse/JDK-8165115 , который был исправлен в Java 9.
В нем говорится:
объекты безопасны для использования несколькими параллельными потоками. Поставщик услуг может объявить, что он является потокобезопасным, установив для атрибута поставщика услуг "ThreadSafe" значение "true" при регистрации поставщика. В противном случае
SecureRandom
class будет синхронизировать доступ к следующимSecureRandomSpi
методы:SecureRandomSpi.engineSetSeed(byte[])
,SecureRandomSpi.engineNextBytes(byte[])
,SecureRandomSpi.engineNextBytes(byte[], SecureRandomParameters)
,SecureRandomSpi.engineGenerateSeed(int)
, а такжеSecureRandomSpi.engineReseed(SecureRandomParameters)
.
Да. Это абсолютно потокобезопасно. На самом деле, я бы пожаловался, что замок слишком агрессивен. Целый engineNextBytes()
синхронизирован.
Если честно, я бы не знал, небезопасно ли это. Проблема с потоками, вероятно, вносит больше случайности:)