LongCache { public long getOrCompute(K key, LongSupplier compute) { if (free.compareAndSet(true, false)) { try { return cache.computeIfAbsent(key, k -> compute.getAsLong()); } finally { free.set(true); } } else { return compute.getAsLong(); } } LongCache(int maxSize); long getOrCompute(K key, LongSupplier compute); @Override String toString();  }
@Test void getOrCompute() { final LongCache<String> lc = new LongCache<>(10); final long actual = lc.getOrCompute("one", () -> 1L); assertEquals(1L, actual); }
@Test void getOrComputeMany() { final LongCache<String> lc = new LongCache<>(2); final long actual1 = lc.getOrCompute("one", () -> 1L); assertEquals(1L, actual1); final long actual2 = lc.getOrCompute("two", () -> 2L); assertEquals(2L, actual2); final long actual3 = lc.getOrCompute("three", () -> 3L); assertEquals(3L, actual3); }
@Test void getOrComputeSlow() throws InterruptedException { final LongCache<String> lc = new LongCache<>(10); Thread t1 = new Thread(() -> lc.getOrCompute("t1", () -> { pause(1000); return 1L; })); t1.start(); pause(100); lc.getOrCompute("main", () -> 2L); t1.join(); }