Недавно я столкнулся с некоторыми высокими сценариями параллелизма на работе, которые требуют блокировки, чтобы обеспечить правильность бизнес -логики, и эффективность после блокировки не должна быть затронута слишком сильно. Первоначальная идея состоит в том, чтобы заблокировать данные с помощью ключевых слов, таких как временные метки и идентификаторы, что обеспечивает параллелизм различных типов обработки данных. Замок детализация, предоставленная собственным API Java, слишком велика, и трудно удовлетворить эти потребности одновременно, поэтому я сам написал несколько простых расширений ...
1. Замок сегмента
Опираясь на идею сегментации concurrenthashmap, создается определенное количество замков, а при его использовании соответствующая блокировка возвращается в соответствии с ключом. Это самая простая, самая высокая производительность и в конечном итоге приняла стратегию блокировки среди нескольких реализаций. Код заключается в следующем:
/*** Замок сегмента, система обеспечивает определенное количество исходных блокировок, получить соответствующую блокировку на основе значения хэша входящего объекта и добавить блокировку* Примечание: если значение хеш -значения объекта будет заблокированным, это может привести к успешному выпущению блокировки !!! */открытый сегмент класса <t> {частные целочисленные сегменты = 16; // Номер по умолчанию сегментов Частный окончательный хэшмап <Integer, reentrantlock> lockmap = new Hashmap <> (); public segmentlock () {init (null, false); } public Segmentlock (целочисленное количество, логическое ярмарка) {init (counts, fair); } private void init (integer counts, boolean fair) {if (counts! = null) {segments = counts; } for (int i = 0; i <segments; i ++) {lockmap.put (i, new reentrantlock (fair)); }} public void lock (t key) {reentrantlock lock = lockmap.get ((key.hashcode () >>> 1) % сегменты); lock.lock (); } public void разблокировка (t key) {reentrantlock lock = lockmap.get ((key.hashcode () >>> 1) % сегменты); lock.unlock (); }}2. Хэш замок
Вторая стратегия блокировки, разработанная на основе вышеуказанного сегментированного блокировки, заключается в достижении истинного мелкозернистого блокировки. Каждый объект с различным значением хэша может получить свою собственную независимую блокировку. В тесте, когда заблокированный код выполняется быстро, эффективность примерно на 30% медленнее, чем блокировка сегмента. Если существует долгая работа, ощущение производительности должно быть лучше. Код заключается в следующем:
открытый класс hashlock <t> {private boolean isfair = false; Приватный окончательный сегмент <T> segmentlock = new Segmentlock <> (); // сегмент блокировки частного окончательного окончательного concurrenthashmap <t, lockinfo> lockmap = new concurrenthashmap <> (); public hashlock () {} public hashlock (boolean fair) {isfair = fair; } public void lock (t key) {lockinfo lockinfo; segmentlock.lock (key); try {lockinfo = lockmap.get (key); if (lockinfo == null) {lockinfo = new lockinfo (isfair); lockmap.put (key, lockinfo); } else {lockinfo.count.incrementAndget (); }} наконец {segmenclock.unlock (key); } lockinfo.lock.lock (); } public void разблокировка (t -ключ) {lockInfo lockinfo = lockmap.get (key); if (lockinfo.count.get () == 1) {segmentlock.lock (key); try {if (lockinfo.count.get () == 1) {lockmap.remove (key); }} наконец {segmenclock.unlock (key); }} lockInfo.count.decrementAndget (); lockinfo.unlock (); } частный статический класс lockinfo {public Reentrantlock Lock; Общественный AtomicInteger Count = новый AtomicInteger (1); private lockinfo (логическая ярмарка) {this.lock = new Reentrantlock (fair); } public void lock () {this.lock.lock (); } public void unlock () {this.lock.unlock (); }}}3. Слабая ссылочная блокировка
Хеш-замки всегда ошибочны, потому что сегментированные замки вводятся для обеспечения синхронизации создания и разрушения блокировки, поэтому был написан третий замк, чтобы добиться лучшей производительности и более тонких замков. Идея этого замка состоит в том, чтобы создать замок с помощью слабых ссылок на Java и передать разрушение блокировки к сборке мусора JVM, чтобы избежать дополнительного потребления.
Немного прискорбно, что, поскольку concurrenthashmap используется в качестве контейнера для блокировки, он не может по -настоящему избавиться от сегментированных замков. Производительность этого замка примерно на 10% быстрее, чем у хэшлока. Код блокировки:
/*** Слабая ссылочная блокировка, обеспечивая независимую функцию блокировки для каждого независимого хэша*/открытого класса SleedHashshlock <t> {private concurrenthashmap <t, shablockref <t, reentrantlock >> lockmap = new concurrenthashmap <> (); Private ReferenceQueue <Reentrantlock> queue = new Referencequeue <> (); public reentrantlock get (t key) {if (lockmap.size ()> 1000) {cleareMptyRef (); } SleedReference <Reentrantlock> lockref = lockmap.get (key); Reentrantlock lock = (lockref == null? Null: lockref.get ()); while (lock == null) {lockmap.putifabsent (key, new Sleasklockref <> (new Reentrantlock (), queue, key)); lockref = lockmap.get (key); lock = (lockref == null? null: lockref.get ()); if (lock! = null) {return lock; } cleareMptyRef (); } return Lock; } @Suppresswarnings ("unchecked") private void uleemptyRef () {reparting <? Extens Reentrantlock> ref; while ((ref = queue.poll ())! = null) {shakeLockRef <T,? Extends Reentrantlock> SleeblockRef = (SholeclockRef <T,? Extends Reentrantlock>) ref; lockmap.remove (sleasklockref.key); }} частный статический окончательный класс SleeblockRef <T, k> расширяет SleedReference <k> {final t key; Private SleaseLockRef (k Ссылка, RESTERSQUEUE <? Super K> Q, T Key) {Super (референт, Q); this.key = key; }}}PostScript
Сначала я хотел использовать LockSupport и AQS для реализации мелкозернистых замков. Как я писал, я обнаружил, что вещи, которые я реализовал, совсем не сильно отличались от тех местных замков Java, поэтому я отказался от инкапсуляции собственных замков Java, что тратило много времени.
Фактически, после внедрения этих мелкозернистых замков у нас есть новые идеи, такие как отправка данных в специальные потоки с помощью идей сегментации, которые могут сократить время блокировки большого количества потоков и оставить их в будущем исследовании ...