Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(revision 1351635)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(working copy)
@@ -16,6 +16,14 @@
  */
 package org.apache.jackrabbit.core.security.authorization.acl;
 
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+
+import javax.jcr.RepositoryException;
+
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.cache.GrowingLRUMap;
@@ -24,9 +32,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
-import java.util.Map;
-
 /**
  * <code>CachingEntryCollector</code> extends <code>EntryCollector</code> by
  * keeping a cache of ACEs per access controlled nodeId.
@@ -73,7 +78,7 @@
         Entries entries = cache.get(nodeId);
         if (entries == null) {
             // fetch entries and update the cache
-            entries = updateCache(node);
+            entries = weaklySynchronizedUpdateCache(node);
         }
         return entries;
     }
@@ -87,7 +92,7 @@
         if (entries == null) {
             // fetch entries and update the cache
             NodeImpl n = getNodeById(nodeId);
-            entries = updateCache(n);
+            entries = weaklySynchronizedUpdateCache(n);
         }
         return entries;
     }
@@ -111,6 +116,36 @@
         return entries;
     }
 
+    private Map<NodeId, Semaphore> sems = new HashMap<NodeId, Semaphore>();
+
+    private Entries weaklySynchronizedUpdateCache(NodeImpl node) throws RepositoryException {
+        NodeId id = node.getNodeId();
+        Semaphore sem = null;
+
+        try {
+            boolean wasBlocked = true;
+
+            synchronized (sems) {
+                sem = sems.get(id);
+                if (sem == null) {
+                    sem = new Semaphore(1);
+                    sems.put(id, sem);
+                    wasBlocked = false;
+                    sem.acquireUninterruptibly();
+                }
+            }
+            Entries r = wasBlocked ? cache.get(id) : null;
+            return r != null ? r : updateCache(node);
+        } finally {
+            sem.release();
+            synchronized (sems) {
+                if (!sem.hasQueuedThreads() && sem.availablePermits() == 1) {
+                    sems.remove(id);
+                }
+            }
+        }
+    }
+
     /**
      * Find the next access control ancestor in the hierarchy 'null' indicates
      * that there is no ac-controlled ancestor.
