public synchronized V get(final K key, final Supplier<V> valueSupplier, final Consumer<V> expireCallback) {
        final var value = cache.get(key);
        if (value != null) {
            value.updateDeadline();
            return value.value;
        }

        final var newValue = new ExpirableValue<>(valueSupplier.get(), expireCallback);
        newValue.updateDeadline();
        cache.put(key, newValue);
        return newValue.value;
    }
@Test
    public void testConcurrentUpdate() throws Exception {
        final var cache = new SimpleCache<Integer, Integer>(executor, 10000L, 10000L);
        final var pool = Executors.newFixedThreadPool(2);
        final var latch = new CountDownLatch(2);
        for (int i = 0; i < 2; i++) {
            final var value = i + 100;
            pool.execute(() -> {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ignored) {
                }
                cache.get(0, () -> value, __ -> {});
                latch.countDown();
            });
        }
        latch.await();
        final var value = cache.get(0, () -> -1, __ -> {});
        Assert.assertTrue(value == 100 || value == 101);
        pool.shutdown();
    }