SecureRandom потокобезопасен?

103

Является ли SecureRandomпоточно? То есть можно ли полагаться на доступ к следующему случайному числу после его инициализации для обеспечения потоковой безопасности? Изучение исходного кода, похоже, показывает, что это так, и этот отчет об ошибке, похоже, указывает на то, что отсутствие документации в качестве потокобезопасности является проблемой javadoc. Кто-нибудь подтвердил, что это действительно потокобезопасный?

Ишай
источник

Ответы:

108

Да, это так. Он расширяется Random, который де-факто всегда имеет потокобезопасную реализацию, а начиная с Java 7 явно гарантирует безопасность потоков.

Если несколько потоков используют один SecureRandom, может возникнуть конфликт, снижающий производительность. С другой стороны, инициализация SecureRandomэкземпляра может быть относительно медленной. Лучше всего использовать глобальный ГСЧ или создать новый для каждого потока - зависит от вашего приложения. ThreadLocalRandomКласс может быть использован в качестве шаблона , чтобы обеспечить решение , которое поддерживает SecureRandom.

Эриксон
источник
3
Спасибо за обновление. Как ни странно, ошибка помечена как закрытая как «не исправить». Но все равно исправили. Да ладно, я не завидую размеру их базы данных об ошибках.
Ишай,
4
инициализация SecureRandomможет быть не только медленной, но и потенциально может зависнуть из-за отсутствия энтропии
Уолтер Тросс
8
Имейте в виду, что ThreadLocalRandom очень легко взломать, поэтому, если вы планируете раскрыть сгенерированное значение миру, используйте SecureRandom вместо jazzy.id.au/default/2010/09/20/…
walv
2
Я собираюсь рискнуть и сказать, что этот ответ неверен. Контракт для Random, который гарантирует безопасность потоков, не привязан к подклассам. Конечно, все другие задокументированные свойства Random не связаны с подклассами, поэтому я не понимаю, почему следует предполагать безопасность потоков.
Президент Джеймс К. Полк
2
@JamesKPolk Отказ сохранить свойство супертипа нарушит принцип заменяемости.
erickson
11

Текущая реализация SecureRandomявляется потокобезопасной, в частности, два метода изменения nextBytes(bytes[])и setSeed(byte[])синхронизируются.

Что ж, насколько я могу судить, все методы мутации в конечном итоге маршрутизируются через эти два метода и SecureRandomпереопределяют несколько методов, Randomчтобы гарантировать это. Что работает, но может быть нестабильным, если реализация будет изменена в будущем.

Лучшее решение - SecureRandomсначала синхронизировать экземпляр вручную . Это означает, что каждый стек вызовов получит две блокировки для одного и того же объекта, но на современных JVM это обычно очень дешево. То есть явная синхронизация себя не представляет особого вреда. Например:

    SecureRandom rnd = ...;

    byte[] b = new byte[NRANDOM_BYTES];
    synchronized (rnd) {
        rnd.nextBytes(b);
    }
Мэтт Куэйл
источник
3
По крайней мере, в JDK 10 SecureRandom основан на провайдере и проверяет, является ли провайдер потокобезопасным, только синхронизируя, если это не так, в nextBytes.
nafg 06
java.security.SecureRandom#nextBytesв Яве 8 не синхронизируется. Не могли бы вы уточнить, в какой версии Java вы нашли синхронизированный #nextBytes?.
Jaime