ConcurrentMaps { public static <K, V> V waitAndRemove(ConcurrentMap<K, V> map, K key) { long start = System.currentTimeMillis(); V value = null; while ((value = map.remove(key)) == null) { if(System.currentTimeMillis() - start < SPIN_THRESHOLD_IN_MILLIS) { continue; } else { String hashCode = String.valueOf(key.hashCode()).intern(); synchronized (hashCode) { if((value = map.remove(key)) == null) { try { hashCode.wait(); } catch (InterruptedException e) { throw CheckedExceptions.wrapAsRuntimeException(e); } } else { break; } } } } return value; }  static V putAndSignal(ConcurrentMap<K, V> map, K key,
            V value); static V waitAndRemove(ConcurrentMap<K, V> map, K key);  }
@Test public void testWaitAndRemove() { final ConcurrentMap<AccessToken, String> map = Maps.newConcurrentMap(); String username = Random.getString(); long salt = Random.getLong(); long timestamp = Time.now(); final AccessToken token0 = createAccessToken(username, salt, timestamp); final AtomicReference<String> actual = new AtomicReference<String>( null); final AtomicBoolean done = new AtomicBoolean(false); Thread waiter = new Thread(new Runnable() { @Override public void run() { actual.set(ConcurrentMaps.waitAndRemove(map, token0)); done.set(true); } }); waiter.start(); AccessToken token = createAccessToken(username, salt, timestamp); Assert.assertNotSame(token0, token); String expected = Random.getString(); ConcurrentMaps.putAndSignal(map, token, expected); while (!done.get()) { continue; } Assert.assertEquals(expected, actual.get()); }