Метод выполняется несколькими потоками, поэтому, если два из них вызовут метод getOrCreateEntity с одинаковым значением и в то же время, они могут закончить созданием двух идентичных объектов, поэтому следующий вызов getEntity вернет два одинаковых объекты, где разрешено только одно.
Я пытался заблокировать каждое уникальное имя объекта, объединив ConcurrentHashMap с ReentrantLock, в целом это работает довольно хорошо, проблемы возникают, когда я пытаюсь удалить запись карты с блокировкой, которая больше не нужна, а затем в какой-то момент я получаю NullPointerException, когда я вызываю метод unlock().
Мне нужна правильная синхронизация для каждого уникального значения.
Мой фиктивный класс для проверки концепции работы
Код: Выделить всё
public class EntityService {
private static final ConcurrentHashMap lockMap = new ConcurrentHashMap();
private static final List entityList = new ArrayList();
public String getOrCreateEntity(String entityName){
lockMap.putIfAbsent(entityName, new ReentrantLock());
lockMap.get(entityName).lock();
try {
return getEntity(entityName).orElseGet(() -> createEntity(entityName));
} finally {
lockMap.get(entityName).unlock(); // tabName.equals(entityName))
.collect(Collectors.toList());
if(result.size() > 1){
throw new RuntimeException();
} else if (result.size() == 1) {
return Optional.of(result.get(0));
} else {
return Optional.empty();
}
}
}
Код: Выделить всё
class ReentrantLockServiceTest extends Specification {
def service = new EntityService()
def executor = Executors.newFixedThreadPool(200)
def "test lock"(){
expect:
for (i in 0..20000) {
executor.execute{ -> service.getOrCreateEntity(RandomUtils.nextInt(1,4) as String) }
}
Thread.sleep(5000)
}
}
Подробнее здесь: https://stackoverflow.com/questions/673 ... enthashmap
Мобильная версия