public V computeIfAbsent(K key, Function<? super K, ? extends V> valueFunction) {
        V value = cache.get(key);
        if (value == null) {
            if (cache.size() < capacity) {
                // use CHM.computeIfAbsent to avoid duplicate calculation of a single key
                value = cache.computeIfAbsent(key, valueFunction);
            } else {
                value = valueFunction.apply(key);
            }
        }
        return value;
    }
@Test
    public void when_addingElementsToCacheMultiThreaded_then_minProperSizeAndElements() {
        int capacity = 20;
        int elementsToAdd = 100;
        int threadCount = 10;
        ConcurrentInitialSetCache<Integer, Integer> cache = new ConcurrentInitialSetCache<>(capacity);
        Runnable runnable = () -> {
            for (int i = 0; i < elementsToAdd; i++) {
                cache.computeIfAbsent(i, Function.identity());
            }
        };

        List<Thread> threadList = IntStream.range(0, threadCount)
                .mapToObj(value -> new Thread(runnable))
                .collect(Collectors.toList());
        threadList.forEach(Thread::start);
        threadList.forEach((ConsumerEx<Thread>) Thread::join);

        assertTrue(cache.cache.size() >= capacity);
        for (int i = 0; i < capacity; i++) {
            assertTrue(cache.cache.containsKey(i));
        }
    }