Re: Чем заменить synchronized (string.intern())
От: vsb Казахстан  
Дата: 14.03.18 09:13
Оценка:
В общем, если кому надо, накидал такой код, вроде должен работать. Поискал альтернативы, по сути примерно так все делают, для оптимизации производительности можно держать не один глобальный лок на map, а список (выбирать по хешу ключа), но тогда надо вместо HashMap ConcurrentHashMap использовать.

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class LockMap {
    interface Unlockable {
        void unlock();
    }

    private final Lock locksLock = new ReentrantLock();
    private final Map<Object, ReferenceCountingLock> locks = new HashMap<Object, ReferenceCountingLock>();

    Unlockable lock(Object key) {
        boolean lockSuccessful = false;
        ReferenceCountingLock rcl = acquire(key);
        try {
            Unlocker unlocker = new Unlocker(key, rcl);
            rcl.lock.lock();
            lockSuccessful = true;
            return unlocker;
        } finally {
            if (!lockSuccessful) {
                release(key, rcl);
            }
        }
    }

    private ReferenceCountingLock acquire(Object key) {
        locksLock.lock();
        try {
            ReferenceCountingLock rcl = locks.get(key);
            if (rcl == null) {
                rcl = new ReferenceCountingLock();
                locks.put(key, rcl);
            }
            rcl.count++;
            return rcl;
        } finally {
            locksLock.unlock();
        }
    }

    private void release(Object key, ReferenceCountingLock rcl) {
        locksLock.lock();
        try {
            rcl.count--;
            if (rcl.count == 0) {
                ReferenceCountingLock oldRCL = locks.remove(key);
                if (rcl != oldRCL) {
                    throw new IllegalStateException();
                }
            }
        } finally {
            locksLock.unlock();
        }
    }

    private static class ReferenceCountingLock {
        private int count;
        private final Lock lock = new ReentrantLock();
    }

    private class Unlocker implements Unlockable {
        private final Object key;
        private final ReferenceCountingLock rcl;

        private Unlocker(Object key, ReferenceCountingLock rcl) {
            this.key = key;
            this.rcl = rcl;
        }

        @Override
        public void unlock() {
            try {
                rcl.lock.unlock();
            } finally {
                release(key, rcl);
            }
        }
    }
}


Использовать так же, как обычные локи:

        Unlockable lock = lockMap.lock(key);
        try {
           ...
        } finally {
            lock.unlock();
        }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.