Proposition: Use ConcurrentHashMap to avoid locking when using the
clientOracleCache.

Review at http://gwt-code-reviews.appspot.com/1425803


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10026 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/rpc/server/RpcServlet.java b/user/src/com/google/gwt/rpc/server/RpcServlet.java
index e094187..f7c5c0d 100644
--- a/user/src/com/google/gwt/rpc/server/RpcServlet.java
+++ b/user/src/com/google/gwt/rpc/server/RpcServlet.java
@@ -33,8 +33,8 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.UnknownHostException;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.zip.GZIPOutputStream;
 
 import javax.servlet.ServletException;
@@ -53,7 +53,7 @@
   protected static final String CLIENT_ORACLE_EXTENSION = ".gwt.rpc";
   private static final boolean DUMP_PAYLOAD = Boolean.getBoolean("gwt.rpc.dumpPayload");
 
-  private final Map<String, SoftReference<ClientOracle>> clientOracleCache = new HashMap<String, SoftReference<ClientOracle>>();
+  private final Map<String, SoftReference<ClientOracle>> clientOracleCache = new ConcurrentHashMap<String, SoftReference<ClientOracle>>();
 
   /**
    * The implementation of the service.
@@ -98,6 +98,17 @@
 
     ClientOracle toReturn;
 
+    // Fast path if the ClientOracle is already cached.
+    if (clientOracleCache.containsKey(permutationStrongName)) {
+      toReturn = clientOracleCache.get(permutationStrongName).get();
+      if (toReturn != null) {
+        return toReturn;
+      }
+    }
+
+    /* Synchronize to make sure expensive calls are executed only once.
+       Double checked locking idiom works here because of volatiles in
+       ConcurrentHashMap.*/
     synchronized (clientOracleCache) {
       if (clientOracleCache.containsKey(permutationStrongName)) {
         toReturn = clientOracleCache.get(permutationStrongName).get();