Выполнение лямбда-выражения HashMap computeIfAbsent - PullRequest
2 голосов
/ 08 мая 2020

У меня есть метод, который использует блокировку для защиты HashMap. С блокировкой метод вызывает computeIfAbsent, а затем снимает блокировку. У меня есть модульный тест, который использует барьер cycli c для создания давления потока для вызова моего метода и выполнения блокировки. Большинство тестовых запусков проходят нормально, но иногда не удается. Это наводит меня на мысль, что даже если вызов computeIfAbsent защищен блокировкой, выполнение / завершение предоставленной ему F (лямбда) - нет.

Я хотел подтвердить это подозрение или узнать о методах, с помощью которых я могу подтвердить это подозрение самостоятельно.

public class Example {
    ReentrantLock lock = new ReentrantLock();
    HashMap<String, Integer> idAssignments = new HashMap<>();
    List<Integer> returnedIds = new ArrayList<>();
    Integer maxId = 0;

    public getAssignedId(String name) {
        lock.lock();
        Integer assignedId = idAssignments.computeIfAbsent(name, generateId);
        lock.unlock()
        return assignedId;
    }
    public generateId(){
        if(returnedIds.size() > 0) {
            return returnedIds.get(returnedIds.size() - 1);
        } else {
            return ++maxId;
        }
    }
}

public class ExampleTest {

    public testGetAssignedId() {
        CyclicBarrier barrier = new CyclicBarrier(500);
        CountDownLatch latch = new CountDownLatch(500);
        HashSet<Integer> receviedIds = new HashSet<>();
        String[] names = new String[] {"one", "two", "three", "four", "five"};
        for (int i = 0; i < 500; i++) {
            poolOf500Threads.submit(() -> {
                barrier.await();
                Integer assignedId = example.getAssignedId(names[i % 5]);
                receviedIds.add(assignedId);
                latch.countDown()
            });
        }
        latch.await();
        assert(receviedIds.size() == 5)  <--- sometimes equals 6
    }
}

Мой тест имеет хэш-набор для отслеживания всех значений, возвращаемых моим методом. Мой тест иногда видит больше уникальных возвращаемых значений, чем уникальные ключи, с которыми я вызываю метод. Могут ли потоки безопасно вызывать computeIfAbsent, но поскольку предыдущий вызов integerProducingMethod еще не сохранен на карте, то некоторые следующие потоки вызывают integerProducingMethod для того же ключа, что и предыдущий?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...