从 ConcurrentHashMap 中删除未使用的 ReentrantLock

问题描述

我有一个服务中的方法,如果存在则获取实体,否则它会创建新的实体并返回(出于问题的目的,假设实体只是一个字符串)。

方法由多个线程执行,因此如果其中两个将同时调用具有相同值的方法 getorCreateEntity,那么他们可以完成创建两个相同的对象,因此下一个 getEntity 调用将返回两个相同的对象,只允许一个

我尝试通过将 ConcurrentHashMapreentrantlock 结合来为每个唯一的实体名称锁定,一般来说效果很好,当我尝试使用不再需要的锁定删除地图条目时会出现问题,然后我在调用 NullPointerException 方法时得到 unlock()

我希望每个唯一值都正确同步。

我的虚拟班级来测试工作概念

public class EntityService {

    private static final ConcurrentHashMap<String,reentrantlock> lockMap = new ConcurrentHashMap<>();

    private static final List<String> 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(); // <--- Nullpointer 
            if(lockMap.containsKey(entityName) && !lockMap.get(entityName).isLocked()){
                lockMap.remove(entityName);
            }
        }

    }

    private String createEntity(String entityName){
        entityList.add(entityName);
        return entityName;
    }

    private Optional<String> getEntity(String entityName){
        List<String> result = entityList.stream()
                .filter(tabName -> 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)
    }

}

我错过了什么?也许有更好的并发类来执行我想要的行为?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)