Index: org/xnio/XnioWorker.java
===================================================================
--- org/xnio/XnioWorker.java	(revision 27374)
+++ org/xnio/XnioWorker.java	(working copy)
@@ -110,17 +110,23 @@
             workerName = "XNIO-" + seq.getAndIncrement();
         }
         name = workerName;
-        taskQueue = new LinkedBlockingQueue<Runnable>();
         final int threadCount = optionMap.get(Options.WORKER_TASK_MAX_THREADS, 16);
-        this.coreSize = optionMap.get(Options.WORKER_TASK_CORE_THREADS, threadCount);
+        this.coreSize = optionMap.get(Options.WORKER_TASK_CORE_THREADS, 0);
+        if (this.coreSize < 3) {
+            this.coreSize = Runtime.getRuntime().availableProcessors();
+        }
         final boolean markThreadAsDaemon = optionMap.get(Options.THREAD_DAEMON, false);
+        RejectedExecutionHandler rejectedExecutionHandler;
+        TaskPoolQueue taskQueue = new TaskPoolQueue();
+        this.taskQueue = taskQueue;
+        rejectedExecutionHandler = taskQueue;
         taskPool = new TaskPool(
-            threadCount, // ignore core threads setting, always fill to max
+            this.coreSize,
             threadCount,
             optionMap.get(Options.WORKER_TASK_KEEPALIVE, 60000), TimeUnit.MILLISECONDS,
             taskQueue,
             new WorkerThreadFactory(threadGroup, optionMap, markThreadAsDaemon),
-            new ThreadPoolExecutor.AbortPolicy());
+            rejectedExecutionHandler);
     }
 
     //==================================================
@@ -868,6 +874,88 @@
         }
     }
 
+    static final class TaskPoolQueue extends LinkedBlockingQueue<Runnable> implements RejectedExecutionHandler {
+
+        private final AtomicInteger waitingCount = new AtomicInteger(0);
+
+        @Override
+        public boolean offer(Runnable r) {
+            if (r instanceof ForceOfferRunnable) {
+                return super.offer(((ForceOfferRunnable)r).task);
+            }
+            super.offer(r); // linked, always true
+            // If no one is waiting for work, we may need to create a new thread
+            if (waitingCount.get() == 0) {
+                if (super.remove(r)) {
+                    // there is no one waiting for work, and no one started work on this one, so force a new thread
+                    return false;
+                }
+                // there is no one waiting for work, but a thread already got the new task
+            }
+            return true;
+        }
+
+        @Override
+        public boolean remove(Object r) {
+            if (r instanceof ForceOfferRunnable) {
+                r = ((ForceOfferRunnable)r).task;
+            }
+            return super.remove(r);
+        }
+
+        @Override
+        public Runnable poll() {
+            try {
+                waitingCount.incrementAndGet();
+                return super.poll();
+            } finally {
+                waitingCount.decrementAndGet();
+            }
+        }
+
+        @Override
+        public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
+            try {
+                waitingCount.incrementAndGet();
+                return super.poll(timeout, unit);
+            } finally {
+                waitingCount.decrementAndGet();
+            }
+        }
+
+        @Override
+        public Runnable take() throws InterruptedException {
+            try {
+                waitingCount.incrementAndGet();
+                return super.take();
+            } finally {
+                waitingCount.decrementAndGet();
+            }
+        }
+
+        @Override
+        public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
+            if (!executor.isShutdown()) {
+                // we don't want to reject tasks, so force the task to queue
+                executor.execute(new ForceOfferRunnable(task));
+            }
+        }
+
+        static private final class ForceOfferRunnable implements Runnable {
+
+            private final Runnable task;
+
+            ForceOfferRunnable(Runnable task) {
+                this.task = task;
+            }
+
+            public void run() {
+                task.run();
+            }
+
+        }
+    }
+
     static class StreamConnectionWrapListener implements ChannelListener<StreamConnection> {
 
         private final FutureResult<ConnectedStreamChannel> futureResult;
