From 06e2bada0a9dbaf54b15e79f3394329addb718b8 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 26 Feb 2018 13:24:25 +0100 Subject: [PATCH] ConcurrentMapCache.get(key, valueLoader) avoids race condition Issue: SPR-16533 --- .../cache/concurrent/ConcurrentMapCache.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java index a8f151652b..eb1303017b 100644 --- a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java +++ b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -137,24 +137,28 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { @SuppressWarnings("unchecked") @Override public T get(Object key, Callable valueLoader) { - if (this.store.containsKey(key)) { - return (T) get(key).get(); + // Try efficient lookup on the ConcurrentHashMap first... + ValueWrapper storeValue = get(key); + if (storeValue != null) { + return (T) storeValue.get(); } - else { - synchronized (this.store) { - if (this.store.containsKey(key)) { - return (T) get(key).get(); - } - T value; - try { - value = valueLoader.call(); - } - catch (Throwable ex) { - throw new ValueRetrievalException(key, valueLoader, ex); - } - put(key, value); - return value; + + // No value found -> load value within full synchronization. + synchronized (this.store) { + storeValue = get(key); + if (storeValue != null) { + return (T) storeValue.get(); } + + T value; + try { + value = valueLoader.call(); + } + catch (Throwable ex) { + throw new ValueRetrievalException(key, valueLoader, ex); + } + put(key, value); + return value; } }