У меня есть метод, который использует блокировку для защиты 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
для того же ключа, что и предыдущий?