Java tutorial
/* * Copyright (c) 2008 Massimiliano Ziccardi * * Licensed 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 it.jnrpe.server; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This class implements a Thread that kills all the JNRPEServerThread * threads that runs for more than a specified number of seconds. * * @author Massimiliano Ziccardi */ public class ThreadTimeoutWatcher extends Thread { /** * The list of the currently executing thread */ private List m_ThreadList = Collections.synchronizedList(new ArrayList()); /** * Checks whether a thread needs to be killed every m_iPollingTime seconds (defaults to 2). */ private static int m_iPollingTime = 2; /** * This variable is used to stop the thread */ private static boolean m_bRun = true; /** * The maximum number of seconds a thread is allowed to run (default 10) */ private static int m_iThreadTimeout = 20; private Log m_Logger = LogFactory.getLog(ThreadTimeoutWatcher.class); /** * Utility class used to store thread informations * * @author Massimiliano Ziccardi */ private static class CThreadData { private Thread m_thread; private long m_lStartTime; CThreadData(Thread t) { m_thread = t; m_lStartTime = System.currentTimeMillis(); } public long getStartTime() { return m_lStartTime; } public Thread getThread() { return m_thread; } } public ThreadTimeoutWatcher() { super("Tindalos"); } /** * Adds the specified thread to the list of threads to be watched * @param t */ public void watch(Thread t) { m_ThreadList.add(new CThreadData(t)); } /** * Stop the thread execution */ public void stopWatching() { m_bRun = false; } /** * Kills the thread identified by the specified thread data * @param td The thread data */ private void killThread(CThreadData td) { Thread t = td.getThread(); if (t.isAlive()) { if (m_Logger.isInfoEnabled()) m_Logger.warn("Killing thread. It was running since " + ((System.currentTimeMillis() - td.getStartTime()) / 1000) + " seconds ago"); ((JNRPEServerThread) t).stopNow(); } } /** * Gets the oldest thread from the list and, if needed, kills it. * Threads no longer running gets removed from the list. * @return <code>true</code> if at leas one thread has been removed from the list. */ private boolean killOldestThread() { // The thread in the first position is always the oldest one CThreadData td = (CThreadData) m_ThreadList.get(0); Thread t = td.getThread(); // If the thread is not alive, or if the thread is older than THREAD_TIMEOUT, it must be killed // and removed from the list if (!t.isAlive() || (System.currentTimeMillis() - td.getStartTime() >= (m_iThreadTimeout * 1000))) { killThread(td); m_ThreadList.remove(0); return true; } return false; } public void setThreadTimeout(int iTimeout) { m_iThreadTimeout = iTimeout; } public void run() { while (m_bRun) { try { Thread.sleep(m_iPollingTime * 1000); } catch (InterruptedException e) { } try { // Keep on killing threads as long as there are threads to kill while (!m_ThreadList.isEmpty() && killOldestThread()) ; } catch (Throwable thr) { // This thread must never die m_Logger.fatal("Error " + thr.getMessage(), thr); } } // Stops all the threads currently running for (Iterator it = m_ThreadList.iterator(); it.hasNext();) killThread((CThreadData) it.next()); } }