View Javadoc

1   /*
2    * Copyright (c) 1998-2004 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.util;
20  
21  import java.util.Collections;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.log4j.Logger;
28  
29  /**
30   * Monitor threads to detect thread failures, and perform corrective action
31   * in case some thread has crashed. <p>
32   *
33   * This class is helpful with respect to debugging deadlock problems, especially
34   * when <code>DUMP_ALL_THREADS</code> is set to true.  This will, at regular
35   * intervals, dump the stack trace of all threads allowing the developer to
36   * identify threads that might have entered into a deadlock situation awaiting
37   * a lock being held by another thread. <p>
38   *
39   * This class requires JDK 5.0, but is not mandatory for general use of Jgroup/ARM,
40   * and as such use of this class may be disabled.
41   *
42   * @author Hein Meling
43   * @since Jgroup 2.1
44   */
45  public class ThreadMonitor
46    extends Thread
47  {
48  
49    ////////////////////////////////////////////////////////////////////////////////////////////
50    // Logger
51    ////////////////////////////////////////////////////////////////////////////////////////////
52  
53    /** Obtain logger for this class */
54    private static final Logger log = Logger.getLogger(ThreadMonitor.class);
55  
56  
57    ////////////////////////////////////////////////////////////////////////////////////////////
58    // Fields
59    ////////////////////////////////////////////////////////////////////////////////////////////
60  
61    /* The default delay to wait between checking thread liveness */
62    private static final int THREAD_DUMP_DELAY = 5000;
63  
64    /*
65     * Option to dump the stack trace of all threads (true),
66     * rather than just the trace for the registered threads (false).
67     */
68    private static boolean DUMP_ALL_THREADS = true;
69  
70    /* Singleton instance of the thread monitor object */
71    private static ThreadMonitor threadMonitor = null;
72  
73    /* The list of threads to watch for failures */
74    private final Set<Thread> threadSet = Collections.synchronizedSet(new HashSet<Thread>(5));
75  
76  
77    ////////////////////////////////////////////////////////////////////////////////////////////
78    // Constructors
79    ////////////////////////////////////////////////////////////////////////////////////////////
80  
81    private ThreadMonitor(String name)
82    {
83      super(name);
84      DUMP_ALL_THREADS = Boolean.getBoolean("jgroup.log.dump.threads");
85    }
86  
87  
88    ////////////////////////////////////////////////////////////////////////////////////////////
89    // Methods
90    ////////////////////////////////////////////////////////////////////////////////////////////
91  
92    /**
93     * Add the given thread to the monitor.
94     */
95    public static void add(Thread thread)
96    {
97      if (threadMonitor == null) {
98        threadMonitor = new ThreadMonitor("ThreadMonitor");
99        threadMonitor.setDaemon(true);
100       threadMonitor.start();
101     }
102     threadMonitor.threadSet.add(thread);
103   }
104 
105 
106   /**
107    * Remove the given thread from being monitored.
108    */
109   public static void remove(Thread thread)
110   {
111     if (threadMonitor == null) {
112       throw new IllegalStateException("Cannot remove entry from monitor; not initialized");
113     }
114     threadMonitor.threadSet.remove(thread);
115   }
116 
117   public static void dumpAllThreads()
118   {
119     Set traceSet = Thread.getAllStackTraces().entrySet();
120     synchronized (traceSet) {
121       for (Iterator iter = traceSet.iterator(); iter.hasNext();) {
122         Map.Entry element = (Map.Entry) iter.next();
123         StackTraceElement[] arr = (StackTraceElement[]) element.getValue();
124         Thread thread = (Thread) element.getKey();
125         log.debug("------------- " + thread.getName()
126             + "." + thread.getId()
127             + ", state=" + thread.getState());
128         for (int i = 0; i < arr.length; i++) {
129           log.debug("  " + arr[i]);
130         }
131       }
132       log.debug("*************************");
133     }
134   }
135 
136 
137   /* (non-Javadoc)
138    * @see java.lang.Runnable#run()
139    */
140   public void run()
141   {
142     while (true) {
143       try {
144         sleep(THREAD_DUMP_DELAY);
145       } catch (InterruptedException e) { }
146 
147       if (DUMP_ALL_THREADS) {
148         if (log.isDebugEnabled()) {
149           dumpAllThreads();
150         }
151       } else {
152         boolean noFailedThreads = true;
153         synchronized (threadSet) {
154           for (Iterator iter = threadSet.iterator(); noFailedThreads && iter.hasNext();) {
155             Thread thread = (Thread) iter.next();
156             if (log.isDebugEnabled()) {
157               StackTraceElement[] trace = thread.getStackTrace();
158               log.debug("--------------------- " + thread.getName());
159               for (int i = 0; i < trace.length; i++) {
160                 log.debug("  " + trace[i]);
161               }
162             }
163             noFailedThreads &= thread.isAlive();
164           }
165           if (log.isDebugEnabled())
166             log.debug("*************************");
167         }
168         if (noFailedThreads == false) {
169           /* One or more threads have failed */
170           if (log.isDebugEnabled())
171             log.debug("One or more threads have failed...");
172         }
173       }
174     }
175   }
176 
177 } // END of ThreadMonitor