2013-07-09 3 views
16

Мне нужно хэшировать несколько ключей из нескольких потоков, используя MessageDigest в критичной для производительности среде. Я узнал, что MessageDigest не является потокобезопасным, поскольку он сохраняет свое состояние в своем объекте. Каким может быть наилучший способ достижения потокового безопасного хеширования ключей?Нужна потоковая безопасность MessageDigest в Java

использования:

MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); 

//somewhere later, just need to hash a key, nothing else 
messageDigest.update(key); 
byte[] bytes = messageDigest.digest(); 

В частности:

  1. Будет ThreadLocal гарантированно работать? Будет ли у него производительность штраф?
  2. Являются ли объекты, возвращенные getInstance разными, и они не мешают друг другу? В документации указано «новый» объект, но я не уверен, что это всего лишь оболочка (общий) общий класс класса?
  3. Если getInstance() возвращает «реальные» новые объекты, целесообразно создать новый экземпляр каждый раз, когда мне нужно, чтобы вычислить хэш? С точки зрения эффективности - как дорого стоит ?

My use case очень прост - просто хэш простой ключ. Я не могу позволить использовать синхронизацию.

Спасибо,

ответ

27

Создать новую MessageDigest экземпляра каждый раз, когда вам нужно один.

Все экземпляры, возвращенные с getInstance(), отличаются. Они должны быть, поскольку они поддерживают отдельные дайджесты (и если этого недостаточно для вас, here's - ссылка на источник).

ThreadLocalможет обеспечить преимущество в производительности при использовании с threadpool для поддержания дорогостоящих объектов. MessageDigest не особенно дорого строится (опять же посмотрите на источник).

+1

Если я вижу codeof GetInstance(), это не похоже, чтобы создать новый объект, а это требует безопасность, чтобы получить объект Object [] OBJS = Security.getImpl Я написал тестовый пример ниже: \t MessageDigest messageDigest1 = MessageDigest.getInstance ("SHA-1"); \t MessageDigest messageDigest2 = MessageDigest.getInstance ("SHA-1"); // обновить и переварить и увидеть, что оба объекта messageDigest различны, а также их внутренние объекты/буферы также различны. Итак, я думаю, что ThreadLocal должен работать. И да, это веб-сервер с пулом потоков. Я буду использовать ThreadLocal. Спасибо, –

+3

@AnilPadia - я ** сильно ** рекомендую ** не ** используя 'ThreadLocal'. Это преждевременная оптимизация. Я написал микро-бенчмарк, который потребовал приблизительно 2 * микро * -секунды для создания нового 'MessageDigest'. Это будет * далеко * перевешиваться кодом, который использует дайджест. – parsifal

+0

Какие проблемы вы видите при использовании ThreadLocal. Даже если у меня есть сотни потоков, там будут сотни таких объектов. Я обнаружил, что объем памяти таких объектов меньше. ThreadLocal отлично работает для меня. Я также тестировал создание объектов, и потребовалось 4 микросекунды. Мне бы очень хотелось знать, почему против ThreadLocal –

3

В качестве альтернативы используйте DigestUtils, защищающую потоки Apache Commons для MessageDigest.

sha1() делает то, что вам нужно:

byte[] bytes = sha1(key)

+0

См. Ответ ниже; DigestUtils не более потокобезопасен, чем MessageDigest, так как DigestUtils.getDigest() просто вызывает MessageDigest.getInstance() и преобразовывает проверенное исключение в исключение без проверки. – Siddhu

+1

Дело в том, что MessageDigest не является потокобезопасным, поэтому повторное использование одного и того же экземпляра в параллельной среде приводит к непредсказуемым результатам. используя новый/другой экземпляр (например, вызывая MessageDigest.getInstance) каждый раз решает вашу проблему. DisgestUtils является потокобезопасным по смыслу, что каждый из его методов удобства использует новый экземпляр MessageDigest, каждый из которых вызывает (после нескольких вызовов) MessageDigest.getInstance, создавая новый экземпляр. например, каждый вызов DigestUtils. sha256Hex («Моя строка»); будет использовать другой экземпляр MessageDigest – Legna

1

DigestUtils не кажется, больше, чем поточно сырой MessageDigest. Все еще использует MessageDigest.getInstance под обложками.

+1

. Дело в том, что MessageDigest не является потокобезопасным, поэтому повторное использование одного и того же экземпляра в параллельной среде приводит к непредсказуемым результатам. с использованием нового/другого экземпляра (например, путем вызова MessageDigest.getInstance) каждый раз решает вашу проблему. DisgestUtils является потокобезопасным в смысле, что каждый из его методов удобства использует новый экземпляр MessageDigest, каждый из которых вызывает (после пары вызовов) MessageDigest.getInstance, создавая новый экземпляр. , например, каждый вызов DigestUtils. sha256Hex («Моя строка»); будет использовать другой экземпляр MessageDigest – Legna

+0

Спасибо за разъяснение. –