You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2016/09/06 05:51:43 UTC

logging-log4j2 git commit: Continuing thread management clean ups: We use a couple of thread pools here and there and I plan on getting these to shutdown consistently and predictably through the API Configurator.shutdown(LoggerContext, long, TimeUnit). W

Repository: logging-log4j2
Updated Branches:
  refs/heads/master fe07f6978 -> 3104d129a


Continuing thread management clean ups: We use a couple of thread pools
here and there and I plan on getting these to shutdown consistently and
predictably through the API Configurator.shutdown(LoggerContext, long,
TimeUnit). When you ask Log4j to shutdown, you can call this API and
expect all threads to stop terminate, no leaks. To do this right,
implement AbstractLifeCycle stop() to call stop(long, TimeUnit) with
default values. This means that most classes that implement stop() will
implement stop(long, TimeUnit) instead and can choose to ignore these
args in simple cases. The next commit will propagate the timeout and
timeUnit values. With Java 8, 'mvn clean test' passes, but not with Java
7 due to the known dependency problem mentioned on the ML. 

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/3104d129
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/3104d129
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/3104d129

Branch: refs/heads/master
Commit: 3104d129a5fc4a71f312038900513e1c5b702ba6
Parents: fe07f69
Author: Gary Gregory <gg...@apache.org>
Authored: Tue Sep 6 01:51:38 2016 -0400
Committer: Gary Gregory <gg...@apache.org>
Committed: Tue Sep 6 01:51:38 2016 -0400

----------------------------------------------------------------------
 .../logging/log4j/core/AbstractLifeCycle.java   |   3 +-
 .../logging/log4j/core/LoggerContext.java       |   9 +-
 .../appender/AbstractOutputStreamAppender.java  |  17 +-
 .../core/appender/AbstractWriterAppender.java   |   8 +-
 .../log4j/core/appender/AsyncAppender.java      |   8 +-
 .../log4j/core/appender/FileAppender.java       |   8 +-
 .../core/appender/MemoryMappedFileAppender.java |   8 +-
 .../core/appender/RandomAccessFileAppender.java |   8 +-
 .../core/appender/RollingFileAppender.java      |   8 +-
 .../RollingRandomAccessFileAppender.java        |   8 +-
 .../log4j/core/appender/SocketAppender.java     |   8 +-
 .../appender/db/AbstractDatabaseAppender.java   |   8 +-
 .../log4j/core/appender/mom/JmsAppender.java    |   9 +-
 .../appender/mom/jeromq/JeroMqAppender.java     |   8 +-
 .../core/appender/mom/kafka/KafkaAppender.java  |   8 +-
 .../core/appender/routing/IdlePurgePolicy.java  |   8 +-
 .../core/appender/routing/RoutingAppender.java  |   8 +-
 .../log4j/core/async/AsyncLoggerConfig.java     |   8 +-
 .../core/async/AsyncLoggerConfigDisruptor.java  |  13 +-
 .../log4j/core/async/AsyncLoggerContext.java    |   7 +-
 .../log4j/core/async/AsyncLoggerDisruptor.java  |  18 +-
 .../core/config/AbstractConfiguration.java      |   7 +-
 .../core/config/ConfigurationScheduler.java     |   6 +-
 .../log4j/core/filter/AbstractFilterable.java   |  20 +-
 .../log4j/core/filter/CompositeFilter.java      |   6 +-
 .../log4j/core/net/server/JmsServer.java        |  12 +-
 .../util/DefaultShutdownCallbackRegistry.java   |  12 +-
 .../log4j/core/util/ExecutorServices.java       |  12 +-
 .../logging/log4j/core/util/WatchManager.java   |   6 +-
 .../log4j/core/appender/HangingAppender.java    |   8 +-
 .../log4j/test/appender/BlockingAppender.java   |   9 +-
 .../log4j/test/appender/DeadlockAppender.java   |   9 +-
 .../log4j/test/appender/ListAppender.java       |   8 +-
 .../log4j/flume/appender/FlumeAppender.java     |   8 +-
 .../log4j/web/Log4jWebInitializerImpl.java      | 550 ++++++++++---------
 35 files changed, 502 insertions(+), 359 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java
index 069362d..8c3c883 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLifeCycle.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core;
 
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.status.StatusLogger;
@@ -120,7 +121,7 @@ public class AbstractLifeCycle implements LifeCycle {
 
     @Override
     public void stop() {
-        this.state = LifeCycle.State.STOPPED;
+        stop(-1, TimeUnit.MILLISECONDS);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 4b3ed88..3fc7fb4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -302,11 +302,6 @@ public class LoggerContext extends AbstractLifeCycle
     }
 
     @Override
-    public void stop() {
-        stop(0, null);
-    }
-
-    @Override
     public boolean stop(long timeout, TimeUnit timeUnit) {
         LOGGER.debug("Stopping LoggerContext[name={}, {}]...", getName(), this);
         configLock.lock();
@@ -336,10 +331,10 @@ public class LoggerContext extends AbstractLifeCycle
             final String source = "LoggerContext \'" + getName() + "\'";
             shutdownEs = ExecutorServices.shutdown(executorService, timeout, timeUnit, source);
             // Do not wait for daemon threads
-            shutdownEsd = ExecutorServices.shutdown(executorServiceDeamons, 0, null, source);
-            this.setStopped();
+            shutdownEsd = ExecutorServices.shutdown(executorServiceDeamons, -1, null, source);
         } finally {
             configLock.unlock();
+            this.setStopped();
         }
         LOGGER.debug("Stopped LoggerContext[name={}, {}]...", getName(), this);
         return shutdownEs && shutdownEsd;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java
index be62a66..dd7cc77 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.core.appender;
 
 import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -131,9 +132,21 @@ public abstract class AbstractOutputStreamAppender<M extends OutputStreamManager
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
         manager.close();
+        setStopped();
+        return true;
+    }
+
+    @Override
+    protected boolean stop(final long timeout, final TimeUnit timeUnit, final boolean changeLifeCycleState) {
+        super.stop(timeout, timeUnit, changeLifeCycleState);
+        manager.close();
+        if (changeLifeCycleState) {
+            setStopped();
+        }
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractWriterAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractWriterAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractWriterAppender.java
index 4e2b835..8b85588 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractWriterAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractWriterAppender.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender;
 
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -115,8 +116,11 @@ public abstract class AbstractWriterAppender<M extends WriterManager> extends Ab
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         manager.close();
+        setStopped();
+        return true;
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
index c14a364..4e85d67 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TransferQueue;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -122,8 +123,9 @@ public final class AsyncAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         LOGGER.trace("AsyncAppender stopping. Queue still has {} events.", queue.size());
         thread.shutdown();
         try {
@@ -137,6 +139,8 @@ public final class AsyncAppender extends AbstractAppender {
             LOGGER.trace("AsyncAppender: {} discarded {} events.", asyncQueueFullPolicy,
                 DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy));
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
index 9e95593..696a236 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -253,10 +254,13 @@ public final class FileAppender extends AbstractOutputStreamAppender<FileManager
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (advertiser != null) {
             advertiser.unadvertise(advertisement);
         }
+        setStopped();
+        return true;
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
index 0949ffd..c1f1aa6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -66,11 +67,14 @@ public final class MemoryMappedFileAppender extends AbstractOutputStreamAppender
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (advertiser != null) {
             advertiser.unadvertise(advertisement);
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
index 1020095..d852e51 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -62,11 +63,14 @@ public final class RandomAccessFileAppender extends AbstractOutputStreamAppender
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (advertiser != null) {
             advertiser.unadvertise(advertisement);
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
index e081f87..44ab7f3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.zip.Deflater;
 
 import org.apache.logging.log4j.core.Filter;
@@ -255,11 +256,14 @@ public final class RollingFileAppender extends AbstractOutputStreamAppender<Roll
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (advertiser != null) {
             advertiser.unadvertise(advertisement);
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
index 5e6f9c7..dae6efd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.zip.Deflater;
 
 import org.apache.logging.log4j.core.Filter;
@@ -70,11 +71,14 @@ public final class RollingRandomAccessFileAppender extends AbstractOutputStreamA
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (advertiser != null) {
             advertiser.unadvertise(advertisement);
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
index c156ecf..42554e1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -216,11 +217,14 @@ public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketM
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (this.advertiser != null) {
             this.advertiser.unadvertise(this.advertisement);
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
index 959df1f..803e0cc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender.db;
 
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -90,11 +91,14 @@ public abstract class AbstractDatabaseAppender<T extends AbstractDatabaseManager
     }
 
     @Override
-    public final void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         if (this.getManager() != null) {
             this.getManager().close();
         }
+        setStopped();
+        return true;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
index b470a38..442243b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java
@@ -18,6 +18,8 @@
 package org.apache.logging.log4j.core.appender.mom;
 
 import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+
 import javax.jms.JMSException;
 import javax.jms.Message;
 import javax.jms.MessageProducer;
@@ -69,9 +71,12 @@ public class JmsAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         this.manager.close();
-        super.stop();
+        setStopped();
+        return true;
     }
 
     @PluginBuilderFactory

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java
index 064ed2c..0f96a21 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java
@@ -20,6 +20,7 @@ package org.apache.logging.log4j.core.appender.mom.jeromq;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
@@ -149,9 +150,12 @@ public final class JeroMqAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         manager.close();
-        super.stop();
+        setStopped();
+        return true;
     }
 
     // not public, handy for testing

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java
index fa7f7e0..6f8e872 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender.mom.kafka;
 
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
@@ -100,9 +101,12 @@ public final class KafkaAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         manager.close();
+        setStopped();
+        return true;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
index f0e1a38..0ce3783 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
@@ -46,7 +46,7 @@ public class IdlePurgePolicy extends AbstractLifeCycle implements PurgePolicy, R
     private final ConcurrentMap<String, Long> appendersUsage = new ConcurrentHashMap<>();
     private RoutingAppender routingAppender;
     private final ConfigurationScheduler scheduler;
-    private volatile ScheduledFuture<?> future = null;
+    private volatile ScheduledFuture<?> future;
 
     public IdlePurgePolicy(final long timeToLive, final long checkInterval, final ConfigurationScheduler scheduler) {
         this.timeToLive = timeToLive;
@@ -60,11 +60,13 @@ public class IdlePurgePolicy extends AbstractLifeCycle implements PurgePolicy, R
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
         if (future != null) {
             future.cancel(true);
         }
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
index 18b7777..1909963 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
@@ -20,6 +20,7 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
@@ -95,8 +96,9 @@ public final class RoutingAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         final Map<String, Appender> map = config.getAppenders();
         for (final Map.Entry<String, AppenderControl> entry : appenders.entrySet()) {
             final String name = entry.getValue().getAppender().getName();
@@ -104,6 +106,8 @@ public final class RoutingAppender extends AbstractAppender {
                 entry.getValue().getAppender().stop();
             }
         }
+        setStopped();
+        return true;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
index 15d3491..170b0da 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.async;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
@@ -124,9 +125,12 @@ public class AsyncLoggerConfig extends LoggerConfig {
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         LOGGER.trace("AsyncLoggerConfig[{}] stopping...", displayName());
-        super.stop();
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
index e864ce8..8e1613f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
@@ -240,12 +240,14 @@ public class AsyncLoggerConfigDisruptor extends AbstractLifeCycle implements Asy
      * Decreases the reference count. If the reference count reached zero, the Disruptor and its associated thread are
      * shut down and their references set to {@code null}.
      */
-    public synchronized void stop() {
+    @Override
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         final Disruptor<Log4jEventWrapper> temp = disruptor;
         if (temp == null) {
             LOGGER.trace("AsyncLoggerConfigDisruptor: disruptor for this configuration already shut down.");
-            return; // disruptor was already shut down by another thread
+            return true; // disruptor was already shut down by another thread
         }
+        setStopping();
         LOGGER.trace("AsyncLoggerConfigDisruptor: shutting down disruptor for this configuration.");
 
         // We must guarantee that publishing to the RingBuffer has stopped before we call disruptor.shutdown().
@@ -263,15 +265,16 @@ public class AsyncLoggerConfigDisruptor extends AbstractLifeCycle implements Asy
         temp.shutdown(); // busy-spins until all events currently in the disruptor have been processed
 
         LOGGER.trace("AsyncLoggerConfigDisruptor: shutting down disruptor executor for this configuration.");
-        // finally, kill the processor thread // TODO time should be picked up when stop(long, TimeUnit) is implemented.
-        ExecutorServices.shutdown(executor, 10, TimeUnit.SECONDS, toString());
+        // finally, kill the processor thread
+        ExecutorServices.shutdown(executor, timeout, timeUnit, toString());
         executor = null; // release reference to allow GC
 
         if (DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy) > 0) {
             LOGGER.trace("AsyncLoggerConfigDisruptor: {} discarded {} events.", asyncQueueFullPolicy,
                     DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy));
         }
-        super.stop();
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
index a06893c..326faf3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.core.async;
 
 import java.net.URI;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
@@ -98,9 +99,11 @@ public class AsyncLoggerContext extends LoggerContext {
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
         loggerDisruptor.stop(); // first stop Disruptor
-        super.stop();
+        super.stop(timeout, timeUnit);
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
index f11b3ed..211b92d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.async;
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.AbstractLifeCycle;
@@ -28,6 +29,7 @@ import org.apache.logging.log4j.status.StatusLogger;
 
 import com.lmax.disruptor.ExceptionHandler;
 import com.lmax.disruptor.RingBuffer;
+import com.lmax.disruptor.TimeoutException;
 import com.lmax.disruptor.WaitStrategy;
 import com.lmax.disruptor.dsl.Disruptor;
 import com.lmax.disruptor.dsl.ProducerType;
@@ -110,12 +112,14 @@ class AsyncLoggerDisruptor extends AbstractLifeCycle {
      * Decreases the reference count. If the reference count reached zero, the Disruptor and its associated thread are
      * shut down and their references set to {@code null}.
      */
-    public synchronized void stop() {
+    @Override
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         final Disruptor<RingBufferLogEvent> temp = getDisruptor();
         if (temp == null) {
             LOGGER.trace("[{}] AsyncLoggerDisruptor: disruptor for this context already shut down.", contextName);
-            return; // disruptor was already shut down by another thread
+            return true; // disruptor was already shut down by another thread
         }
+        setStopping();
         LOGGER.debug("[{}] AsyncLoggerDisruptor: shutting down disruptor for this context.", contextName);
 
         // We must guarantee that publishing to the RingBuffer has stopped before we call disruptor.shutdown().
@@ -130,7 +134,12 @@ class AsyncLoggerDisruptor extends AbstractLifeCycle {
             } catch (final InterruptedException e) { // ignored
             }
         }
-        temp.shutdown(); // busy-spins until all events currently in the disruptor have been processed
+        try {
+            // busy-spins until all events currently in the disruptor have been processed
+            temp.shutdown(timeout, timeUnit);
+        } catch (TimeoutException e) {
+            temp.shutdown();
+        } 
 
         LOGGER.trace("[{}] AsyncLoggerDisruptor: shutting down disruptor executor.", contextName);
         executor.shutdown(); // finally, kill the processor thread
@@ -140,7 +149,8 @@ class AsyncLoggerDisruptor extends AbstractLifeCycle {
             LOGGER.trace("AsyncLoggerDisruptor: {} discarded {} events.", asyncQueueFullPolicy,
                     DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy));
         }
-        super.stop();
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 0e053a1..b165366 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -34,6 +34,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Appender;
@@ -275,8 +276,9 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
      * Tear down the configuration.
      */
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         this.setStopping();
+        super.stop(timeout, timeUnit, false);
         LOGGER.trace("Stopping {}...", this);
 
         // Stop the components that are closest to the application first:
@@ -361,11 +363,12 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
         }
         configurationScheduler.stop();
 
-        super.stop();
         if (advertiser != null && advertisement != null) {
             advertiser.unadvertise(advertisement);
         }
+        setStopped();
         LOGGER.debug("Stopped {} OK", this);
+        return true;
     }
 
     private List<Appender> getAsyncAppenders(final Appender[] all) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
index 0a87148..a17166d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationScheduler.java
@@ -52,12 +52,14 @@ public class ConfigurationScheduler extends AbstractLifeCycle {
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
         if (executorService != null) {
             LOGGER.debug("{} shutting down threads in {}", SIMPLE_NAME, executorService);
             executorService.shutdown();
         }
-        super.stop();
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java
index e57b58d..e12067e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/AbstractFilterable.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.core.filter;
 
 import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.AbstractLifeCycle;
 import org.apache.logging.log4j.core.Filter;
@@ -144,12 +145,29 @@ public abstract class AbstractFilterable extends AbstractLifeCycle implements Fi
      * Cleanup the Filter.
      */
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         this.setStopping();
         if (filter != null) {
             filter.stop();
         }
         this.setStopped();
+        return true;
+    }
+
+    /**
+     * Cleanup the Filter.
+     */
+    protected boolean stop(final long timeout, final TimeUnit timeUnit, final boolean changeLifeCycleState) {
+        if (changeLifeCycleState) {
+            this.setStopping();
+        }
+        if (filter != null) {
+            filter.stop();
+        }
+        if (changeLifeCycleState) {
+            this.setStopped();
+        }
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
index 33f72d5..a539418 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/CompositeFilter.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
@@ -132,12 +133,13 @@ public final class CompositeFilter extends AbstractLifeCycle implements Iterable
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         this.setStopping();
         for (final Filter filter : filters) {
             filter.stop();
         }
-        this.setStopped();
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
index c68b067..0341461 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/JmsServer.java
@@ -97,19 +97,19 @@ public class JmsServer extends LogEventListener implements MessageListener, Life
         }
     }
 
-    @Override
+    @Override    
     public void stop() {
+        stop(-1, TimeUnit.MILLISECONDS);
+    }
+    
+    @Override
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         try {
             messageConsumer.close();
         } catch (final JMSException e) {
             LOGGER.debug("Exception closing {}", messageConsumer, e);
         }
         jmsManager.close();
-    }
-
-    @Override
-    public boolean stop(long timeout, TimeUnit timeUnit) {
-        stop();
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
index 1aab6c7..611abdc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
@@ -150,11 +150,16 @@ public class DefaultShutdownCallbackRegistry implements ShutdownCallbackRegistry
         Runtime.getRuntime().addShutdownHook(thread);
     }
 
+    @Override    
+    public void stop() {
+        stop(-1, TimeUnit.MILLISECONDS);
+    }
+
     /**
      * Cancels the shutdown thread only if this is started.
      */
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
         if (state.compareAndSet(State.STARTED, State.STOPPING)) {
             try {
                 removeShutdownHook();
@@ -162,11 +167,6 @@ public class DefaultShutdownCallbackRegistry implements ShutdownCallbackRegistry
                 state.set(State.STOPPED);
             }
         }
-    }
-
-    @Override
-    public boolean stop(long timeout, TimeUnit timeUnit) {
-        stop();
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ExecutorServices.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ExecutorServices.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ExecutorServices.java
index 4ceb70b..efd7ed1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ExecutorServices.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ExecutorServices.java
@@ -29,19 +29,25 @@ public class ExecutorServices {
     /**
      * Shuts down the given {@link ExecutorService} in an orderly fashion. Disables new tasks from submission and then
      * waits for existing tasks to terminate. Eventually cancels running tasks if too much time elapses.
+     * <p>
+     * If the timeout is < 0, then a plain shutdown takes place.
+     * </p>
      * 
      * @param executorService
      *            the pool to shutdown.
      * @param timeout
      *            the maximum time to wait
-     * @param source
-     *            use this string in any log messages.
      * @param timeUnit
      *            the time unit of the timeout argument
+     * @param source
+     *            use this string in any log messages.
      * @return {@code true} if the given executor terminated and {@code false} if the timeout elapsed before
      *         termination.
      */
     public static boolean shutdown(ExecutorService executorService, long timeout, TimeUnit timeUnit, String source) {
+        if (executorService.isTerminated()) {
+            return true;
+        }
         executorService.shutdown(); // Disable new tasks from being submitted
         if (timeout > 0 && timeUnit == null) {
             throw new IllegalArgumentException(
@@ -66,6 +72,8 @@ public class ExecutorServices {
                 // Preserve interrupt status
                 Thread.currentThread().interrupt();
             }
+        } else {
+            executorService.shutdown();
         }
         return true;
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
index 1004f81..f592a7c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
@@ -69,9 +69,11 @@ public class WatchManager extends AbstractLifeCycle {
     }
 
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
         future.cancel(true);
-        super.stop();
+        setStopped();
+        return true;
     }
 
     public void watchFile(final File file, final FileWatcher watcher) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
index 36a652e..44f44c0 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginFactory;
 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
 
 import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
 
 @Plugin(name = "Hanging", category = "Core", elementType = "appender", printObject = true)
 public class HangingAppender extends AbstractAppender {
@@ -76,12 +77,15 @@ public class HangingAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         try {
             Thread.sleep(shutdownDelay);
         } catch (final InterruptedException ignore) {
             // ignore
         }
+        setStopped();
+        return true;
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
index aa3c13e..c863382 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.test.appender;
 
+import java.util.concurrent.TimeUnit;
+
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.appender.AbstractAppender;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
@@ -46,9 +48,12 @@ public class BlockingAppender extends AbstractAppender {
         }
     }
     @Override
-    public void stop() {
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         running = false;
-        super.stop();
+        setStopped();
+        return true;
     }
 
     @PluginFactory

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
index 7dd0c62..57dc4d8 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.test.appender;
 
+import java.util.concurrent.TimeUnit;
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LoggingException;
@@ -46,14 +48,17 @@ public class DeadlockAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         thread.start();
         try {
             thread.join();
         } catch (final Exception ex) {
             System.out.println("Thread interrupted");
         }
+        setStopped();
+        return true;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
index 30aa41b..6ecf5c3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -144,8 +145,9 @@ public class ListAppender extends AbstractAppender {
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         final Layout<? extends Serializable> layout = getLayout();
         if (layout != null) {
             final byte[] bytes = layout.getFooter();
@@ -153,6 +155,8 @@ public class ListAppender extends AbstractAppender {
                 write(bytes);
             }
         }
+        setStopped();
+        return true;
     }
 
     public synchronized ListAppender clear() {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
----------------------------------------------------------------------
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
index 874ac54..3e2cf10 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.flume.appender;
 
 import java.io.Serializable;
 import java.util.Locale;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -106,9 +107,12 @@ public final class FlumeAppender extends AbstractAppender implements FlumeEventF
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
         manager.close();
+        setStopped();
+        return true;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3104d129/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java
----------------------------------------------------------------------
diff --git a/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java b/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java
index 3fcc7d9..287e253 100644
--- a/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java
+++ b/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java
@@ -1,274 +1,276 @@
-/*
- * 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.logging.log4j.web;
-
-import java.net.URI;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.servlet.ServletContext;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.AbstractLifeCycle;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.async.AsyncLoggerContext;
-import org.apache.logging.log4j.core.config.Configurator;
-import org.apache.logging.log4j.core.impl.ContextAnchor;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
-import org.apache.logging.log4j.core.lookup.Interpolator;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.selector.ContextSelector;
-import org.apache.logging.log4j.core.selector.NamedContextSelector;
-import org.apache.logging.log4j.core.util.Loader;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.core.util.SetUtils;
-import org.apache.logging.log4j.spi.LoggerContextFactory;
-import org.apache.logging.log4j.util.LoaderUtil;
-
-/**
- * This class initializes and deinitializes Log4j no matter how the initialization occurs.
- */
-final class Log4jWebInitializerImpl extends AbstractLifeCycle implements Log4jWebLifeCycle {
-
-    private static final String WEB_INF = "/WEB-INF/";
-
-    static {
-        if (Loader.isClassAvailable("org.apache.logging.log4j.core.web.JNDIContextFilter")) {
-            throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct "
-                    + "log4j-web artifact. This is not supported and could cause serious runtime problems. Please"
-                    + "remove the log4j-web JAR file from your application.");
-        }
-    }
-
-    private final Map<String, String> map = new ConcurrentHashMap<>();
-    private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator(map));
-    private final ServletContext servletContext;
-
-    private String name;
-    private NamedContextSelector namedContextSelector;
-    private LoggerContext loggerContext;
-
-    private Log4jWebInitializerImpl(final ServletContext servletContext) {
-        this.servletContext = servletContext;
-        this.map.put("hostName", NetUtils.getLocalHostname());
-    }
-
-    /**
-     * Initializes the Log4jWebLifeCycle attribute of a ServletContext. Those who wish to obtain this object should use
-     * the {@link org.apache.logging.log4j.web.WebLoggerContextUtils#getWebLifeCycle(javax.servlet.ServletContext)}
-     * method instead.
-     *
-     * @param servletContext
-     *        the ServletContext to initialize
-     * @return a new Log4jWebLifeCycle
-     * @since 2.0.1
-     */
-    protected static Log4jWebInitializerImpl initialize(final ServletContext servletContext) {
-        final Log4jWebInitializerImpl initializer = new Log4jWebInitializerImpl(servletContext);
-        servletContext.setAttribute(SUPPORT_ATTRIBUTE, initializer);
-        return initializer;
-    }
-
-    @Override
-    public synchronized void start() {
-        if (this.isStopped() || this.isStopping()) {
-            throw new IllegalStateException("Cannot start this Log4jWebInitializerImpl after it was stopped.");
-        }
-
-        // only do this once
-        if (this.isInitialized()) {
-            super.setStarting();
-
-            this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
-            final String location = this.substitutor.replace(this.servletContext
-                    .getInitParameter(LOG4J_CONFIG_LOCATION));
-            final boolean isJndi = "true".equalsIgnoreCase(this.servletContext
-                    .getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));
-
-            if (isJndi) {
-                this.initializeJndi(location);
-            } else {
-                this.initializeNonJndi(location);
-            }
-            if (this.loggerContext instanceof AsyncLoggerContext) {
-                ((AsyncLoggerContext) this.loggerContext).setUseThreadLocals(false);
-            }
-
-            this.servletContext.setAttribute(CONTEXT_ATTRIBUTE, this.loggerContext);
-            super.setStarted();
-        }
-    }
-
-    private void initializeJndi(final String location) {
-        final URI configLocation = getConfigURI(location);
-
-        if (this.name == null) {
-            throw new IllegalStateException("A log4jContextName context parameter is required");
-        }
-
-        LoggerContext context;
-        final LoggerContextFactory factory = LogManager.getFactory();
-        if (factory instanceof Log4jContextFactory) {
-            final ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
-            if (selector instanceof NamedContextSelector) {
-                this.namedContextSelector = (NamedContextSelector) selector;
-                context = this.namedContextSelector.locateContext(this.name, this.servletContext, configLocation);
-                ContextAnchor.THREAD_CONTEXT.set(context);
-                if (context.isInitialized()) {
-                    context.start();
-                }
-                ContextAnchor.THREAD_CONTEXT.remove();
-            } else {
-                LOGGER.warn("Potential problem: Selector is not an instance of NamedContextSelector.");
-                return;
-            }
-        } else {
-            LOGGER.warn("Potential problem: LoggerContextFactory is not an instance of Log4jContextFactory.");
-            return;
-        }
-        this.loggerContext = context;
-        LOGGER.debug("Created logger context for [{}] using [{}].", this.name, context.getClass().getClassLoader());
-    }
-
-    private void initializeNonJndi(final String location) {
-        if (this.name == null) {
-            this.name = this.servletContext.getServletContextName();
-            LOGGER.debug("Using the servlet context name \"{}\".", this.name);
-        }
-        if (this.name == null) {
-            this.name = this.servletContext.getContextPath();
-            LOGGER.debug("Using the servlet context context-path \"{}\".", this.name);
-        }
-
-        if (this.name == null && location == null) {
-            LOGGER.error("No Log4j context configuration provided. This is very unusual.");
-            this.name = new SimpleDateFormat("yyyyMMdd_HHmmss.SSS").format(new Date());
-        }
-
-        final URI uri = getConfigURI(location);
-        this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), uri, this.servletContext);
-    }
-
-    private URI getConfigURI(final String location) {
-        try {
-            String configLocation = location;
-            if (configLocation == null) {
-                final String[] paths = SetUtils.prefixSet(servletContext.getResourcePaths(WEB_INF), WEB_INF + "log4j2");
-                LOGGER.debug("getConfigURI found resource paths {} in servletContext at [{}]", Arrays.toString(paths), WEB_INF);
-                if (paths.length == 1) {
-                    configLocation = paths[0];
-                } else if (paths.length > 1) {
-                    final String prefix = WEB_INF + "log4j2-" + this.name + ".";
-                    boolean found = false;
-                    for (final String str : paths) {
-                        if (str.startsWith(prefix)) {
-                            configLocation = str;
-                            found = true;
-                            break;
-                        }
-                    }
-                    if (!found) {
-                        configLocation = paths[0];
-                    }
-                }
-            }
-            if (configLocation != null) {
-                final URL url = servletContext.getResource(configLocation);
-                if (url != null) {
-                    final URI uri = url.toURI();
-                    LOGGER.debug("getConfigURI found resource [{}] in servletContext at [{}]", uri, configLocation);
-                    return uri;
-                }
-            }
-        } catch (final Exception ex) {
-            // Just try passing the location.
-        }
-        if (location != null) {
-            try {
-                final URI correctedFilePathUri = NetUtils.toURI(location);
-                LOGGER.debug("getConfigURI found [{}] in servletContext at [{}]", correctedFilePathUri, location);
-                return correctedFilePathUri;
-            } catch (final Exception e) {
-                LOGGER.error("Unable to convert configuration location [{}] to a URI", location, e);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public synchronized void stop() {
-        if (!this.isStarted() && !this.isStopped()) {
-            throw new IllegalStateException("Cannot stop this Log4jWebInitializer because it has not started.");
-        }
-
-        // only do this once
-        if (this.isStarted()) {
-            this.setStopping();
-            if (this.loggerContext != null) {
-                LOGGER.debug("Removing LoggerContext for [{}].", this.name);
-                this.servletContext.removeAttribute(CONTEXT_ATTRIBUTE);
-                if (this.namedContextSelector != null) {
-                    this.namedContextSelector.removeContext(this.name);
-                }
-                this.loggerContext.stop();
-                this.loggerContext.setExternalContext(null);
-                this.loggerContext = null;
-            }
-            this.setStopped();
-        }
-    }
-
-    @Override
-    public void setLoggerContext() {
-        if (this.loggerContext != null) {
-            ContextAnchor.THREAD_CONTEXT.set(this.loggerContext);
-        }
-    }
-
-    @Override
-    public void clearLoggerContext() {
-        ContextAnchor.THREAD_CONTEXT.remove();
-    }
-
-    @Override
-    public void wrapExecution(final Runnable runnable) {
-        this.setLoggerContext();
-
-        try {
-            runnable.run();
-        } finally {
-            this.clearLoggerContext();
-        }
-    }
-
-    private ClassLoader getClassLoader() {
-        try {
-            // if container is Servlet 3.0, use its getClassLoader method
-            // this may look odd, but the call below will throw NoSuchMethodError if user is on Servlet 2.5
-            // we compile against 3.0 to support Log4jServletContainerInitializer, but we don't require 3.0
-            return this.servletContext.getClassLoader();
-        } catch (final Throwable ignore) {
-            // LOG4J2-248: use TCCL if possible
-            return LoaderUtil.getThreadContextClassLoader();
-        }
-    }
-
-}
+/*
+ * 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.logging.log4j.web;
+
+import java.net.URI;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletContext;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.AbstractLifeCycle;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.async.AsyncLoggerContext;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.impl.ContextAnchor;
+import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import org.apache.logging.log4j.core.lookup.Interpolator;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.selector.ContextSelector;
+import org.apache.logging.log4j.core.selector.NamedContextSelector;
+import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.NetUtils;
+import org.apache.logging.log4j.core.util.SetUtils;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.util.LoaderUtil;
+
+/**
+ * This class initializes and deinitializes Log4j no matter how the initialization occurs.
+ */
+final class Log4jWebInitializerImpl extends AbstractLifeCycle implements Log4jWebLifeCycle {
+
+    private static final String WEB_INF = "/WEB-INF/";
+
+    static {
+        if (Loader.isClassAvailable("org.apache.logging.log4j.core.web.JNDIContextFilter")) {
+            throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct "
+                    + "log4j-web artifact. This is not supported and could cause serious runtime problems. Please"
+                    + "remove the log4j-web JAR file from your application.");
+        }
+    }
+
+    private final Map<String, String> map = new ConcurrentHashMap<>();
+    private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator(map));
+    private final ServletContext servletContext;
+
+    private String name;
+    private NamedContextSelector namedContextSelector;
+    private LoggerContext loggerContext;
+
+    private Log4jWebInitializerImpl(final ServletContext servletContext) {
+        this.servletContext = servletContext;
+        this.map.put("hostName", NetUtils.getLocalHostname());
+    }
+
+    /**
+     * Initializes the Log4jWebLifeCycle attribute of a ServletContext. Those who wish to obtain this object should use
+     * the {@link org.apache.logging.log4j.web.WebLoggerContextUtils#getWebLifeCycle(javax.servlet.ServletContext)}
+     * method instead.
+     *
+     * @param servletContext
+     *        the ServletContext to initialize
+     * @return a new Log4jWebLifeCycle
+     * @since 2.0.1
+     */
+    protected static Log4jWebInitializerImpl initialize(final ServletContext servletContext) {
+        final Log4jWebInitializerImpl initializer = new Log4jWebInitializerImpl(servletContext);
+        servletContext.setAttribute(SUPPORT_ATTRIBUTE, initializer);
+        return initializer;
+    }
+
+    @Override
+    public synchronized void start() {
+        if (this.isStopped() || this.isStopping()) {
+            throw new IllegalStateException("Cannot start this Log4jWebInitializerImpl after it was stopped.");
+        }
+
+        // only do this once
+        if (this.isInitialized()) {
+            super.setStarting();
+
+            this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
+            final String location = this.substitutor.replace(this.servletContext
+                    .getInitParameter(LOG4J_CONFIG_LOCATION));
+            final boolean isJndi = "true".equalsIgnoreCase(this.servletContext
+                    .getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));
+
+            if (isJndi) {
+                this.initializeJndi(location);
+            } else {
+                this.initializeNonJndi(location);
+            }
+            if (this.loggerContext instanceof AsyncLoggerContext) {
+                ((AsyncLoggerContext) this.loggerContext).setUseThreadLocals(false);
+            }
+
+            this.servletContext.setAttribute(CONTEXT_ATTRIBUTE, this.loggerContext);
+            super.setStarted();
+        }
+    }
+
+    private void initializeJndi(final String location) {
+        final URI configLocation = getConfigURI(location);
+
+        if (this.name == null) {
+            throw new IllegalStateException("A log4jContextName context parameter is required");
+        }
+
+        LoggerContext context;
+        final LoggerContextFactory factory = LogManager.getFactory();
+        if (factory instanceof Log4jContextFactory) {
+            final ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
+            if (selector instanceof NamedContextSelector) {
+                this.namedContextSelector = (NamedContextSelector) selector;
+                context = this.namedContextSelector.locateContext(this.name, this.servletContext, configLocation);
+                ContextAnchor.THREAD_CONTEXT.set(context);
+                if (context.isInitialized()) {
+                    context.start();
+                }
+                ContextAnchor.THREAD_CONTEXT.remove();
+            } else {
+                LOGGER.warn("Potential problem: Selector is not an instance of NamedContextSelector.");
+                return;
+            }
+        } else {
+            LOGGER.warn("Potential problem: LoggerContextFactory is not an instance of Log4jContextFactory.");
+            return;
+        }
+        this.loggerContext = context;
+        LOGGER.debug("Created logger context for [{}] using [{}].", this.name, context.getClass().getClassLoader());
+    }
+
+    private void initializeNonJndi(final String location) {
+        if (this.name == null) {
+            this.name = this.servletContext.getServletContextName();
+            LOGGER.debug("Using the servlet context name \"{}\".", this.name);
+        }
+        if (this.name == null) {
+            this.name = this.servletContext.getContextPath();
+            LOGGER.debug("Using the servlet context context-path \"{}\".", this.name);
+        }
+
+        if (this.name == null && location == null) {
+            LOGGER.error("No Log4j context configuration provided. This is very unusual.");
+            this.name = new SimpleDateFormat("yyyyMMdd_HHmmss.SSS").format(new Date());
+        }
+
+        final URI uri = getConfigURI(location);
+        this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), uri, this.servletContext);
+    }
+
+    private URI getConfigURI(final String location) {
+        try {
+            String configLocation = location;
+            if (configLocation == null) {
+                final String[] paths = SetUtils.prefixSet(servletContext.getResourcePaths(WEB_INF), WEB_INF + "log4j2");
+                LOGGER.debug("getConfigURI found resource paths {} in servletContext at [{}]", Arrays.toString(paths), WEB_INF);
+                if (paths.length == 1) {
+                    configLocation = paths[0];
+                } else if (paths.length > 1) {
+                    final String prefix = WEB_INF + "log4j2-" + this.name + ".";
+                    boolean found = false;
+                    for (final String str : paths) {
+                        if (str.startsWith(prefix)) {
+                            configLocation = str;
+                            found = true;
+                            break;
+                        }
+                    }
+                    if (!found) {
+                        configLocation = paths[0];
+                    }
+                }
+            }
+            if (configLocation != null) {
+                final URL url = servletContext.getResource(configLocation);
+                if (url != null) {
+                    final URI uri = url.toURI();
+                    LOGGER.debug("getConfigURI found resource [{}] in servletContext at [{}]", uri, configLocation);
+                    return uri;
+                }
+            }
+        } catch (final Exception ex) {
+            // Just try passing the location.
+        }
+        if (location != null) {
+            try {
+                final URI correctedFilePathUri = NetUtils.toURI(location);
+                LOGGER.debug("getConfigURI found [{}] in servletContext at [{}]", correctedFilePathUri, location);
+                return correctedFilePathUri;
+            } catch (final Exception e) {
+                LOGGER.error("Unable to convert configuration location [{}] to a URI", location, e);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized boolean stop(final long timeout, final TimeUnit timeUnit) {
+        if (!this.isStarted() && !this.isStopped()) {
+            throw new IllegalStateException("Cannot stop this Log4jWebInitializer because it has not started.");
+        }
+
+        // only do this once
+        if (this.isStarted()) {
+            this.setStopping();
+            if (this.loggerContext != null) {
+                LOGGER.debug("Removing LoggerContext for [{}].", this.name);
+                this.servletContext.removeAttribute(CONTEXT_ATTRIBUTE);
+                if (this.namedContextSelector != null) {
+                    this.namedContextSelector.removeContext(this.name);
+                }
+                this.loggerContext.stop();
+                this.loggerContext.setExternalContext(null);
+                this.loggerContext = null;
+            }
+            this.setStopped();
+        }
+        return super.stop(timeout, timeUnit);
+    }
+
+    @Override
+    public void setLoggerContext() {
+        if (this.loggerContext != null) {
+            ContextAnchor.THREAD_CONTEXT.set(this.loggerContext);
+        }
+    }
+
+    @Override
+    public void clearLoggerContext() {
+        ContextAnchor.THREAD_CONTEXT.remove();
+    }
+
+    @Override
+    public void wrapExecution(final Runnable runnable) {
+        this.setLoggerContext();
+
+        try {
+            runnable.run();
+        } finally {
+            this.clearLoggerContext();
+        }
+    }
+
+    private ClassLoader getClassLoader() {
+        try {
+            // if container is Servlet 3.0, use its getClassLoader method
+            // this may look odd, but the call below will throw NoSuchMethodError if user is on Servlet 2.5
+            // we compile against 3.0 to support Log4jServletContainerInitializer, but we don't require 3.0
+            return this.servletContext.getClassLoader();
+        } catch (final Throwable ignore) {
+            // LOG4J2-248: use TCCL if possible
+            return LoaderUtil.getThreadContextClassLoader();
+        }
+    }
+
+}