sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1393350 - in /sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util: DaemonThread.java ReferenceQueueConsumer.java Threads.java
Date Wed, 03 Oct 2012 08:40:55 GMT
Author: desruisseaux
Date: Wed Oct  3 08:40:55 2012
New Revision: 1393350

URL: http://svn.apache.org/viewvc?rev=1393350&view=rev
Log:
Maintains a chained list of DaemonThreads to terminate when a OSGi bundle is desactivated.

Modified:
    sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java
    sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
    sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java

Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java?rev=1393350&r1=1393349&r2=1393350&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java (original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java Wed
Oct  3 08:40:55 2012
@@ -16,15 +16,18 @@
  */
 package org.apache.sis.internal.util;
 
+import java.util.List;
+import java.util.ArrayList;
+
 
 /**
- * Base class for all daemon threads in the SIS library. This class provides a
- * {@link #isKillRequested()} flag which shall be tested by the daemon threads.
- * It is okay to test this flag only when catching {@link InterruptedException},
- * as below:
+ * Base class for all daemon threads in the SIS library. All {@code DaemonThread} instances
are
+ * expected to run for the whole JVM lifetime (they are <strong>not</strong>
executor threads).
+ * This class provides a {@link #isKillRequested()} flag which shall be tested by the subclasses.
+ * It is okay to test this flag only when catching {@link InterruptedException}, as below:
  *
  * {@preformat java
- *     while (someCondition) {
+ *     while (true) {
  *         try {
  *             someObject.wait();
  *         } catch (InterruptedException e) {
@@ -40,57 +43,118 @@ package org.apache.sis.internal.util;
  * @version 0.3
  * @module
  */
-public class DaemonThread extends Thread {
+abstract class DaemonThread extends Thread {
     /**
-     * Set to {@code true} when the {@link #kill()} method has been invoked.
+     * The previous element in a chain of {@code DaemonThread}s. We maintain a linked list
of
+     * {@code DaemonThread} to be killed when {@link #killAll(DaemonThread)} will be invoked.
+     * We do not rely on the thread listed by the {@link Threads#RESOURCE_DISPOSERS} group
+     * because in an OSGi context, we need to handle separately the threads created by each
+     * SIS module.
+     */
+    private final DaemonThread previous;
+
+    /**
+     * Set to {@code true} when a kill is requested.
      */
     private volatile boolean killRequested;
 
     /**
      * Creates a new daemon thread. This constructor sets the daemon flag to {@code true}.
+     * <p>
+     * We need to maintain a list of daemon threads created by each SIS module in order to
+     * kill them at shutdown time (not strictly necessary for pure JSEE applications, but
+     * required in OSGi environment). Each module using {@code DaemonThread} shall maintain
+     * its <strong>own</strong> list (don't use the list of another module),
like below:
+     *
+     * {@preformat java
+     *     class MyInternalClass {
+     *         static DaemonThread lastCreatedDaemon;
+     *     }
+     *
+     *     class AnOtherClass {
+     *         private static final MyDaemonThread;
+     *         static {
+     *             synchronized (MyInternalClass.class) {
+     *                 MyInternalClass.lastCreatedDaemon = myDaemonThread = new MyDaemonThread(
+     *                         Threads.RESOURCE_DISPOSERS, "MyThread", MyInternalClass.lastCreatedDaemon);
+     *         }
+     *     }
+     * }
+     *
+     * See {@link ReferenceQueueConsumer} for a real example.
      *
      * @param group The thread group.
      * @param name  The thread name.
+     * @param lastCreatedDaemon The previous element in a chain of {@code DaemonThread}s,
+     *        or {@code null}. Each SIS module shall maintain its own chain, if any.
      */
-    protected DaemonThread(final ThreadGroup group, final String name) {
+    protected DaemonThread(final ThreadGroup group, final String name, final DaemonThread
lastCreatedDaemon) {
         super(group, name);
+        previous = lastCreatedDaemon;
         setDaemon(true);
     }
 
     /**
-     * Returns {@code true} if {@link #kill()} has been invoked.
+     * Must be overridden by subclass for performing the actual work.
+     */
+    @Override
+    public abstract void run();
+
+    /**
+     * Returns {@code true} if this daemon thread shall terminate.
+     * This happen at shutdown time.
      *
-     * @return {@code true} if {@link #kill()} has been invoked.
+     * @return {@code true} if this daemon thread shall terminate.
      */
     protected final boolean isKillRequested() {
         return killRequested;
     }
 
     /**
-     * Kills all the given threads (ignoring null arguments),
+     * Sends a kill signal to all threads in the chain starting by the given thread,
      * and waits for the threads to die before to return.
+     * <p>
+     * <strong>This method is for internal use by Apache SIS shutdown hooks only.</strong>
+     * Users should never invoke this method explicitely.
      *
-     * @param  stopWaitingAt Value of {@link System#nanoTime()} when to stop waiting.
-     *         This is used for preventing the shutdown to block an indefinite amount of
time.
-     * @param  threads The threads to kill. Null arguments are silently ignored.
+     * @param  first The first thread in the chain of threads to kill.
+     * @param  stopWaitingAt A {@link System#nanoTime()} value telling when to stop waiting.
+     *         This is used for preventing shutdown process to block an indefinite amount
of time.
      * @throws InterruptedException If an other thread invoked {@link #interrupt()} while
      *         we were waiting for the daemon threads to die.
+     *
+     * @see Threads#shutdown(long)
      */
-    static void kill(final long stopWaitingAt, final DaemonThread... threads)
-            throws InterruptedException
-    {
-        for (final DaemonThread thread : threads) {
-            if (thread != null) {
-                thread.killRequested = true;
-                thread.interrupt();
-            }
+    static void killAll(final DaemonThread first, final long stopWaitingAt) throws InterruptedException
{
+        for (DaemonThread thread=first; thread!=null; thread=thread.previous) {
+            thread.killRequested = true;
+            thread.interrupt();
         }
-        for (final DaemonThread thread : threads) {
-            if (thread != null) {
-                final long delay = stopWaitingAt - System.nanoTime();
-                if (delay <= 0) break;
-                thread.join(delay);
+        for (DaemonThread thread=first; thread!=null; thread=thread.previous) {
+            final long delay = stopWaitingAt - System.nanoTime();
+            if (delay <= 0) break;
+            thread.join(delay);
+        }
+    }
+
+    /**
+     * Returns the names of dead threads, or {@code null} if none. The returned list should
+     * always be null. A non-empty list would be a symptom for a severe problem, probably
+     * requiring an application reboot.
+     *
+     * @param  first The first thread in the chain of threads to verify.
+     * @return The name of dead threads, or {@code null} if none.
+     */
+    static List<String> listDeadThreads(final DaemonThread first) {
+        List<String> list = null;
+        for (DaemonThread thread=first; thread!=null; thread=thread.previous) {
+            if (!thread.isAlive()) {
+                if (list == null) {
+                    list = new ArrayList<String>();
+                }
+                list.add(thread.getName());
             }
         }
+        return list;
     }
 }

Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java?rev=1393350&r1=1393349&r2=1393350&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
(original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
Wed Oct  3 08:40:55 2012
@@ -56,13 +56,15 @@ import org.apache.sis.util.logging.Loggi
  */
 public final class ReferenceQueueConsumer<T> extends DaemonThread {
     /**
-     * The default thread.
+     * The singleton instance of the {@code ReferenceQueueConsumer} thread.
      */
     public static final ReferenceQueueConsumer<Object> DEFAULT;
     static {
+        synchronized (Threads.class) {
+            Threads.lastCreatedDaemon = DEFAULT = new ReferenceQueueConsumer<Object>(Threads.lastCreatedDaemon);
+        }
         // Call to Thread.start() must be outside the constructor
         // (Reference: Goetz et al.: "Java Concurrency in Practice").
-        DEFAULT = new ReferenceQueueConsumer<Object>("ReferenceQueueConsumer");
         DEFAULT.start();
     }
 
@@ -76,18 +78,17 @@ public final class ReferenceQueueConsume
     /**
      * Constructs a new thread as a daemon thread. This thread will be sleeping most of the
time.
      * It will run only only a few nanoseconds every time a new {@link Reference} is enqueded.
-     *
-     * @param name The thread name. This name appears in the debugger.
      */
-    private ReferenceQueueConsumer(final String name) {
-        super(Threads.RESOURCE_DISPOSERS, name);
-        setPriority(Thread.MAX_PRIORITY);
+    private ReferenceQueueConsumer(final DaemonThread lastCreatedDaemon) {
+        super(Threads.RESOURCE_DISPOSERS, "ReferenceQueueConsumer", lastCreatedDaemon);
+        setPriority(Thread.MAX_PRIORITY - 2);
         // The above line sets the priority to the maximal value allowed by the
         // RESOURCE_DISPOSERS group, which is actually lower than MAX_PRIORITY.
     }
 
     /**
      * Loop to be run during the virtual machine lifetime.
+     * Public as an implementation side-effect; <strong>do not invoke explicitly!</strong>
      */
     @Override
     public final void run() {
@@ -117,7 +118,7 @@ public final class ReferenceQueueConsume
                     continue;
                 }
             } catch (InterruptedException exception) {
-                // Probably the 'kill()' method has been invoked.
+                // Probably the 'killAll' method has been invoked.
                 // We need to test 'isKillRequested()' below.
             } catch (Throwable exception) {
                 Logging.unexpectedException(getClass(), "run", exception);

Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java?rev=1393350&r1=1393349&r2=1393350&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java (original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java Wed Oct
 3 08:40:55 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.util;
 
+import org.apache.sis.util.Static;
 import org.apache.sis.util.logging.Logging;
 
 
@@ -29,7 +30,7 @@ import org.apache.sis.util.logging.Loggi
  * @version 0.3
  * @module
  */
-public final class Threads {
+final class Threads extends Static {
     /**
      * The parent of every threads declared in this class. This parent will be declared as
close
      * as possible to the root of all thread groups (i.e. not as an application thread subgroup).
@@ -56,17 +57,40 @@ public final class Threads {
      * quickly, and the benefit of executing those tasks soon is more resources made available.
      */
     static final ThreadGroup RESOURCE_DISPOSERS = new ThreadGroup(SIS, "ResourceDisposers")
{
+        /* Constructor */ {
+            setMaxPriority(Thread.NORM_PRIORITY + 3);
+        }
         @Override public void uncaughtException(final Thread thread, final Throwable exception)
{
             Logging.severeException(Logging.getLogger("org.apache.sis"), thread.getClass(),
"run", exception);
         }
     };
-    static {
-        RESOURCE_DISPOSERS.setMaxPriority(Thread.NORM_PRIORITY + 2);
-    }
+
+    /**
+     * The tail of a chain of {@code DaemonThread}s created by the {@code sis-utility} module.
+     * Other modules need to maintain their own chain, if any. See the {@link DaemonThread}
+     * javadoc for more information.
+     */
+    static DaemonThread lastCreatedDaemon;
 
     /**
      * Do not allows instantiation of this class.
      */
     private Threads() {
     }
+
+    /**
+     * Sends a kill signal to all daemon threads created by the {@code sis-utility} module,
+     * and waits for the threads to die before to return.
+     * <p>
+     * <strong>This method is for internal use by Apache SIS shutdown hooks only.</strong>
+     * Users should never invoke this method explicitely.
+     *
+     * @param  stopWaitingAt A {@link System#nanoTime()} value telling when to stop waiting.
+     *         This is used for preventing shutdown process to block an indefinite amount
of time.
+     * @throws InterruptedException If an other thread invoked {@link #interrupt()} while
+     *         we were waiting for the daemon threads to die.
+     */
+    static synchronized void shutdown(final long stopWaitingAt) throws InterruptedException
{
+        DaemonThread.killAll(lastCreatedDaemon, stopWaitingAt);
+    }
 }



Mime
View raw message