diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
index 4e504ea74b66fad29830ac6dfb812f863045f1d3..93d7bf1babec36eda7826e93d8a3f83cf66c0aba 100644
--- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
@@ -172,15 +172,20 @@ class EstablishmentManager {
                     if (_queuedOutbound.size() > MAX_QUEUED_OUTBOUND) {
                         rejected = true;
                     } else {
-                        List<OutNetMessage> newQueued = new ArrayList(1);
+                        List<OutNetMessage> newQueued = new ArrayList(MAX_QUEUED_PER_PEER);
                         List<OutNetMessage> queued = _queuedOutbound.putIfAbsent(to, newQueued);
                         if (queued == null)
                             queued = newQueued;
-                        queueCount = queued.size();
-                        if (queueCount < MAX_QUEUED_PER_PEER)
-                            queued.add(msg);
+                        // this used to be inside a synchronized (_outboundStates) block,
+                        // but that's now a CHM, so protect the ArrayList
+                        // There are still races possible but this should prevent AIOOBE and NPE
+                        synchronized (queued) {
+                            queueCount = queued.size();
+                            if (queueCount < MAX_QUEUED_PER_PEER)
+                                queued.add(msg);
+                            deferred = _queuedOutbound.size();
+                        }
                     }
-                    deferred = _queuedOutbound.size();
                 } else {
                     // must have a valid session key
                     byte[] keyBytes = addr.getIntroKey();
@@ -212,9 +217,14 @@ class EstablishmentManager {
             if (state != null) {
                 state.addMessage(msg);
                 List<OutNetMessage> queued = _queuedOutbound.remove(to);
-                if (queued != null)
-                    for (int i = 0; i < queued.size(); i++)
-                        state.addMessage(queued.get(i));
+                if (queued != null) {
+                    // see comments above
+                    synchronized (queued) {
+                        for (OutNetMessage m : queued) {
+                            state.addMessage(m);
+                        }
+                    }
+                }
             }
         
         if (rejected) {
@@ -399,8 +409,12 @@ class EstablishmentManager {
                 // there shouldn't have been queued messages for this active state, but just in case...
                 List<OutNetMessage> queued = _queuedOutbound.remove(state.getRemoteHostId());
                 if (queued != null) {
-                    for (int i = 0; i < queued.size(); i++) 
-                        state.addMessage(queued.get(i));
+                    // see comments above
+                    synchronized (queued) {
+                        for (OutNetMessage m : queued) {
+                            state.addMessage(m);
+                        }
+                    }
                 }
                 
                 //admitted = locked_admitQueued();