Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java	(revision 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java	(working copy)
@@ -204,7 +204,7 @@
         createSystemUsers(systemUserManager, this.systemSession, adminId, anonymousId);
 
         // init default ac-provider-factory
-        acProviderFactory = new AccessControlProviderFactoryImpl();
+        acProviderFactory = new AccessControlProviderFactoryImpl(new SessionPoolFactory());
         acProviderFactory.init(this.systemSession);
 
         // create the workspace access manager
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionPoolFactory.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionPoolFactory.java	(revision 0)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionPoolFactory.java	(working copy)
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+/**
+ * Factory used to create a pool of {@code SystemSession} instances.
+ */
+public class SessionPoolFactory {
+
+    SessionPoolFactory() {}
+
+    public Pool createPool() {
+        return new Pool();
+    }
+
+    public class Pool {
+
+        boolean initialized;
+        SessionImpl[] sessions;
+        volatile int sindex = 0;
+
+        // private constructor
+        private Pool() {}
+
+        /**
+         * Initializes this instance of a system session pool using the specified
+         * {@code session} and the given {@code size}. The init method
+         * creates new instances of SystemSession; the specified session will not
+         * be held in the pool.
+         *
+         * @param session Session used to initialize the pool.
+         * @param size The desired number of system sessions to held in the pool.
+         * @throws IllegalStateException If this pool has been initialized before
+         * @throws IllegalArgumentException If the pool size is &lt;1
+         * @throws RepositoryException If an error occurs.
+         */
+        public void init(SessionImpl session, int size) throws RepositoryException {
+            if (initialized) {
+                throw new IllegalStateException("Already initialized");
+            }
+            if (size < 1) {
+                throw new IllegalArgumentException("Invalid pool size " + size);
+            }
+
+            String workspaceName = session.getWorkspace().getName();
+            Repository repository = session.getRepository();
+            if (!(repository instanceof RepositoryImpl)) {
+                throw new IllegalArgumentException("Invalid repository implementation.");
+            }
+            RepositoryImpl repoImpl = (RepositoryImpl) repository;
+            sessions = new SessionImpl[size];
+            for (int i = 0; i < size; i++) {
+                sessions[i] = SystemSession.create(repoImpl.getRepositoryContext(), repoImpl.getConfig().getWorkspaceConfig(workspaceName));
+            }
+
+            initialized = true;
+        }
+
+        /**
+         * Disposes this pool and calls {@link javax.jcr.Session#logout()} on
+         * all sessions held by it.
+         */
+        public void dispose() {
+            checkInitialized();
+            for (SessionImpl s : sessions) {
+                if (s.isLive()) {
+                    s.logout();
+                }
+            }
+            initialized = false;
+            sessions = null;
+        }
+
+        /**
+         * Returns a session out of the session pool.
+         *
+         * @return a session out of the pool.
+         */
+        public SessionImpl getSession() {
+            checkInitialized();
+            int n = sindex++;
+            return sessions[(n & Integer.MAX_VALUE) % sessions.length];
+        }
+
+        private void checkInitialized() {
+            if (!initialized) {
+                throw new IllegalStateException("Not yet initialized");
+            }
+        }
+    }
+}
\ No newline at end of file
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java	(revision 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java	(working copy)
@@ -56,6 +56,14 @@
     public static final String PARAM_OMIT_DEFAULT_PERMISSIONS = "omit-default-permission";
 
     /**
+     * Constant for the name of the configuration option "session-pool". The
+     * option is intended to be a flag indicating if a session pool
+     * should be created for the configured access control provider. If the
+     * config option is missing no session pool will be created (default).
+     */
+    public static final String PARAM_SESSION_POOL = "session-pool";
+
+    /**
      * the system session this provider has been created for.
      */
     protected SessionImpl session;
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java	(revision 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java	(working copy)
@@ -16,20 +16,23 @@
  */
 package org.apache.jackrabbit.core.security.authorization;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.config.BeanConfig;
 import org.apache.jackrabbit.core.config.WorkspaceSecurityConfig;
 import org.apache.jackrabbit.core.security.authorization.acl.ACLProvider;
 import org.apache.jackrabbit.core.security.user.UserAccessControlProvider;
-import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.RepositoryImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import java.util.Collections;
-import java.util.Map;
-
 /**
  * Default implementation of the AccessControlProviderFactory
  */
@@ -40,12 +43,21 @@
      */
     private static final Logger log = LoggerFactory.getLogger(AccessControlProviderFactoryImpl.class);
 
+    private final SessionPoolFactory sessionPoolFactory;
+
     /**
      * The name of the security workspace (containing users...)
      */
     private String secWorkspaceName;
     private String defaultWorkspaceName;
 
+    public AccessControlProviderFactoryImpl() {
+        this(null);
+    }
+
+    public AccessControlProviderFactoryImpl(SessionPoolFactory sessionPool) {
+        this.sessionPoolFactory = sessionPool;
+    }
     //---------------------------------------< AccessControlProviderFactory >---
     /**
      * @see AccessControlProviderFactory#init(Session)
@@ -71,11 +83,18 @@
             throws RepositoryException {
         String workspaceName = systemSession.getWorkspace().getName();
         AccessControlProvider prov;
-        Map props;
+        Map<Object, Object> props;
         if (config != null && config.getAccessControlProviderConfig() != null) {
             BeanConfig bc = config.getAccessControlProviderConfig();
             prov = bc.newInstance(AccessControlProvider.class);
             props = bc.getParameters();
+
+            // create a new session pool for the ac provider if the factory is
+            // present and the access control provider configuration contains
+            // the config option "session-pool".
+            if (sessionPoolFactory != null && Boolean.parseBoolean(bc.getParameters().getProperty(AbstractAccessControlProvider.PARAM_SESSION_POOL, "false"))) {
+                props.put(AbstractAccessControlProvider.PARAM_SESSION_POOL, sessionPoolFactory.createPool());
+            }
         } else {
             log.debug("No ac-provider configuration for workspace " + workspaceName + " -> using defaults.");
             if (workspaceName.equals(secWorkspaceName) && !workspaceName.equals(defaultWorkspaceName)) {
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java	(revision 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java	(working copy)
@@ -19,6 +19,7 @@
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.security.SecurityConstants;
@@ -94,6 +95,11 @@
      */
     private EntryCollector entryCollector;
 
+    /**
+     * Session pool containing multiple system session (see JCR-3394)
+     */
+    private SessionPoolFactory.Pool sessionPool;
+
     //----------------------------------------------< AccessControlProvider >---
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlProvider#init(Session, Map)
@@ -114,13 +120,23 @@
             initRootACL(session, systemEditor);
         }
 
+        if (configuration.containsKey(PARAM_SESSION_POOL)) {
+            sessionPool = (SessionPoolFactory.Pool) configuration.get(PARAM_SESSION_POOL);
+            String propname = "org.apache.jackrabbit.core.security.authorization.acl.ACLProvider.sessionpoolsize";
+            int size = Integer.parseInt(System.getProperty(propname, "8"));
+            sessionPool.init(session, size);
+        }
+
         entryCollector = createEntryCollector(session);
     }
 
     @Override
     public void close() {
-        super.close();        
+        super.close();
         entryCollector.close();
+        if (sessionPool != null) {
+            sessionPool.dispose();
+        }
     }
 
     /**
@@ -234,7 +250,7 @@
         } else if (isReadOnly(principals)) {
             return getReadOnlyPermissions();
         } else {
-            return new CompiledPermissionsImpl(principals, session, entryCollector, this, true);
+            return new CompiledPermissionsImpl(principals, session, sessionPool, entryCollector, this, true);
         }
     }
 
@@ -246,7 +262,7 @@
         if (isAdminOrSystem(principals)) {
             return true;
         } else {
-            CompiledPermissions cp = new CompiledPermissionsImpl(principals, session, entryCollector, this, false);
+            CompiledPermissions cp = new CompiledPermissionsImpl(principals, session, sessionPool, entryCollector, this, false);
             try {
                 return cp.canRead(null, rootNodeId);
             } finally {
@@ -266,7 +282,7 @@
      * @throws RepositoryException If an error occurs.
      */
     protected EntryCollector createEntryCollector(SessionImpl systemSession) throws RepositoryException {
-        return new CachingEntryCollector(systemSession, rootNodeId);
+        return new CachingEntryCollector(systemSession, rootNodeId, sessionPool);
     }
 
     //------------------------------------------------------------< private >---
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 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java	(working copy)
@@ -24,6 +24,7 @@
 
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.cache.GrowingLRUMap;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
@@ -60,7 +61,19 @@
      * @throws RepositoryException If an error occurs.
      */
     CachingEntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
-        super(systemSession, rootID);
+        this(systemSession, rootID, null);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param systemSession A system session.
+     * @param rootID The id of the root node.
+     * @param sessionPool A pool of system sessions or {@code null}.
+     * @throws RepositoryException If an error occurs.
+     */
+    CachingEntryCollector(SessionImpl systemSession, NodeId rootID, SessionPoolFactory.Pool sessionPool) throws RepositoryException {
+        super(systemSession, rootID, sessionPool);
         cache = new EntryCache();
 
         // for testing purposes, see JCR-2950
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java	(revision 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CompiledPermissionsImpl.java	(working copy)
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.security.authorization.acl;
 
 import org.apache.jackrabbit.api.JackrabbitWorkspace;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.cache.GrowingLRUMap;
 import org.apache.jackrabbit.core.ItemImpl;
 import org.apache.jackrabbit.core.ItemManager;
@@ -53,6 +54,7 @@
 
     private final List<String> principalNames;
     private final SessionImpl session;
+    private final SessionPoolFactory.Pool sessionPool;
     private final EntryCollector entryCollector;
     private final AccessControlUtils util;
 
@@ -66,9 +68,11 @@
     private final Object monitor = new Object();
 
     CompiledPermissionsImpl(Set<Principal> principals, SessionImpl session,
+                            SessionPoolFactory.Pool sessionPool,
                             EntryCollector entryCollector, AccessControlUtils util,
                             boolean listenToEvents) throws RepositoryException {
         this.session = session;
+        this.sessionPool = sessionPool;
         this.entryCollector = entryCollector;
         this.util = util;
 
@@ -153,6 +157,7 @@
         boolean existingNode = false;
         NodeImpl node;
 
+        SessionImpl session = getSession();
         ItemManager itemMgr = session.getItemManager();
         try {
             ItemImpl item = itemMgr.getItem(absPath);
@@ -273,6 +278,14 @@
         return canRead;
     }
 
+    private SessionImpl getSession() {
+        if (sessionPool != null) {
+            return sessionPool.getSession();
+        } else {
+            return session;
+        }
+    }
+
     //----------------------------------------< ACLModificationListener >---
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlListener#acModified(org.apache.jackrabbit.core.security.authorization.AccessControlModifications)
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java	(revision 1477059)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.SessionPoolFactory;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
@@ -66,6 +67,8 @@
      */
     protected final NodeId rootID;
 
+    private final SessionPoolFactory.Pool sessionPool;
+
     private final EventListener moveListener;
 
     /**
@@ -75,8 +78,20 @@
      * @throws RepositoryException
      */
     protected EntryCollector(SessionImpl systemSession, NodeId rootID) throws RepositoryException {
+        this(systemSession, rootID, null);
+    }
+
+    /**
+     *
+     * @param systemSession
+     * @param rootID
+     * @param sessionPool
+     * @throws RepositoryException
+     */
+    protected EntryCollector(SessionImpl systemSession, NodeId rootID, SessionPoolFactory.Pool sessionPool) throws RepositoryException {
         this.systemSession = systemSession;
         this.rootID = rootID;
+        this.sessionPool = sessionPool;
 
         ObservationManager observationMgr = systemSession.getWorkspace().getObservationManager();
         /*
@@ -214,7 +229,13 @@
      * @throws javax.jcr.RepositoryException
      */
     NodeImpl getNodeById(NodeId nodeId) throws RepositoryException {
-        return ((NodeImpl) systemSession.getItemManager().getItem(nodeId));
+        SessionImpl s;
+        if (sessionPool != null) {
+            s = sessionPool.getSession();
+        } else {
+            s = systemSession;
+        }
+        return ((NodeImpl) s.getItemManager().getItem(nodeId));
     }
 
     //------------------------------------------------------< EventListener >---
