Java/Threads/Utilities
Содержание
- 1 Busy Flag
- 2 Early return
- 3 Exception call back
- 4 Finds a resource with the given name.
- 5 Listing all threads and threadgroups in the VM.
- 6 Return a new instance of the given class. Checks the ThreadContext classloader first, then uses the System classloader.
- 7 Sleep utilities
- 8 Thread-based logging utility
- 9 Transition Detector
- 10 View current Threads in a table
Busy Flag
<source lang="java">
/*
* * Copyright (c) 1997-1999 Scott Oaks and Henry Wong. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and * without fee is hereby granted. * * This sample source code is provided for example only, * on an unsupported, as-is basis. * * AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. AUTHOR SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. * * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). AUTHOR * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR * HIGH RISK ACTIVITIES. */
public class BusyFlag {
protected Thread busyflag = null; protected int busycount = 0; public synchronized void getBusyFlag() { while (tryGetBusyFlag() == false) { try { wait(); } catch (Exception e) {} } } public synchronized boolean tryGetBusyFlag() { if (busyflag == null) { busyflag = Thread.currentThread(); busycount = 1; return true; } if (busyflag == Thread.currentThread()) { busycount++; return true; } return false; } public synchronized void freeBusyFlag() { if (getBusyFlagOwner() == Thread.currentThread()) { busycount--; if (busycount == 0) { busyflag = null; notify(); } } } public synchronized Thread getBusyFlagOwner() { return busyflag; }
} /*
* * Copyright (c) 1997-1999 Scott Oaks and Henry Wong. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and * without fee is hereby granted. * * This sample source code is provided for example only, * on an unsupported, as-is basis. * * AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. AUTHOR SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. * * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). AUTHOR * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR * HIGH RISK ACTIVITIES. */
public class CondVar {
private BusyFlag SyncVar; public CondVar() { this(new BusyFlag()); } public CondVar(BusyFlag sv) { SyncVar = sv; } public void cvWait() throws InterruptedException { cvTimedWait(SyncVar, 0); } public void cvWait(BusyFlag sv) throws InterruptedException { cvTimedWait(sv, 0); } public void cvTimedWait(int millis) throws InterruptedException { cvTimedWait(SyncVar, millis); } public void cvTimedWait(BusyFlag sv, int millis) throws InterruptedException { int i = 0; InterruptedException errex = null; synchronized (this) { // You must own the lock in order to use this method if (sv.getBusyFlagOwner() != Thread.currentThread()) { throw new IllegalMonitorStateException("current thread not owner"); } // Release the lock (Completely) while (sv.getBusyFlagOwner() == Thread.currentThread()) { i++; sv.freeBusyFlag(); } // Use wait() method try { if (millis == 0) { wait(); } else { wait(millis); } } catch (InterruptedException iex) { errex = iex; } } // Obtain the lock (Return to original state) for (; i>0; i--) { sv.getBusyFlag(); } if (errex != null) throw errex; return; } public void cvSignal() { cvSignal(SyncVar); } public synchronized void cvSignal(BusyFlag sv) { // You must own the lock in order to use this method if (sv.getBusyFlagOwner() != Thread.currentThread()) { throw new IllegalMonitorStateException("current thread not owner"); } notify(); } public void cvBroadcast() { cvBroadcast(SyncVar); } public synchronized void cvBroadcast(BusyFlag sv) { // You must own the lock in order to use this method if (sv.getBusyFlagOwner() != Thread.currentThread()) { throw new IllegalMonitorStateException("current thread not owner"); } notifyAll(); }
}
</source>
Early return
<source lang="java">
public class EarlyReturn extends Object {
private volatile int value; public EarlyReturn(int v) { value = v; } public synchronized void setValue(int v) { if (value != v) { value = v; notifyAll(); } } public synchronized boolean waitUntilAtLeast(int minValue, long msTimeout) throws InterruptedException { System.out.println("value=" + value + ",minValue=" + minValue); long endTime = System.currentTimeMillis() + msTimeout; long msRemaining = msTimeout; while ((value < minValue) && (msRemaining > 0L)) { System.out.println("about to: wait(" + msRemaining + ")"); wait(msRemaining); msRemaining = endTime - System.currentTimeMillis(); System.out.println("back from wait(), new msRemaining=" + msRemaining); } System.out.println("leaving waitUntilAtLeast() - " + "value=" + value + ",minValue=" + minValue); // May have timed out, or may have met value, return (value >= minValue); } public static void main(String[] args) { try { final EarlyReturn er = new EarlyReturn(0); Runnable r = new Runnable() { public void run() { try { Thread.sleep(1500); er.setValue(2); Thread.sleep(500); er.setValue(3); Thread.sleep(500); er.setValue(4); } catch (Exception x) { x.printStackTrace(); } } }; Thread t = new Thread(r); t.start(); System.out.println("waitUntilAtLeast(5, 3000)"); long startTime = System.currentTimeMillis(); boolean retVal = er.waitUntilAtLeast(5, 3000); long elapsedTime = System.currentTimeMillis() - startTime; System.out.println(elapsedTime + " ms, retVal=" + retVal); } catch (InterruptedException ix) { ix.printStackTrace(); } }
}
</source>
Exception call back
<source lang="java">
import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class ExceptionCallbackMain extends Object implements ExceptionListener {
private int exceptionCount; public ExceptionCallbackMain() { exceptionCount = 0; } public void exceptionOccurred(Exception x, Object source) { exceptionCount++; System.err.println("EXCEPTION #" + exceptionCount + ", source=" + source); x.printStackTrace(); } public static void main(String[] args) { ExceptionListener xListener = new ExceptionCallbackMain(); ExceptionCallback ec = new ExceptionCallback(xListener); }
} class ExceptionCallback extends Object {
private Set exceptionListeners; private Thread internalThread; private volatile boolean noStopRequested; public ExceptionCallback(ExceptionListener[] initialGroup) { init(initialGroup); } public ExceptionCallback(ExceptionListener initialListener) { ExceptionListener[] group = new ExceptionListener[1]; group[0] = initialListener; init(group); } public ExceptionCallback() { init(null); } private void init(ExceptionListener[] initialGroup) { System.out.println("initializing..."); exceptionListeners = Collections.synchronizedSet(new HashSet()); if (initialGroup != null) { for (int i = 0; i < initialGroup.length; i++) { addExceptionListener(initialGroup[i]); } } noStopRequested = true; Runnable r = new Runnable() { public void run() { try { runWork(); } catch (Exception x) { sendException(x); } } }; internalThread = new Thread(r); internalThread.start(); } private void runWork() { try { makeConnection(); } catch (IOException x) { sendException(x); } String str = null; int len = determineLength(str); } private void makeConnection() throws IOException { String portStr = "jexp20"; int port = 0; try { port = Integer.parseInt(portStr); } catch (NumberFormatException x) { sendException(x); port = 80; } connectToPort(port); } private void connectToPort(int portNum) throws IOException { throw new IOException("connection refused"); } private int determineLength(String s) { return s.length(); } public void stopRequest() { noStopRequested = false; internalThread.interrupt(); } public boolean isAlive() { return internalThread.isAlive(); } private void sendException(Exception x) { if (exceptionListeners.size() == 0) { x.printStackTrace(); return; } synchronized (exceptionListeners) { Iterator iter = exceptionListeners.iterator(); while (iter.hasNext()) { ExceptionListener l = (ExceptionListener) iter.next(); l.exceptionOccurred(x, this); } } } public void addExceptionListener(ExceptionListener l) { if (l != null) { exceptionListeners.add(l); } } public void removeExceptionListener(ExceptionListener l) { exceptionListeners.remove(l); } public String toString() { return getClass().getName() + "[isAlive()=" + isAlive() + "]"; }
} interface ExceptionListener {
public void exceptionOccurred(Exception x, Object source);
}
</source>
Finds a resource with the given name.
<source lang="java">
/*
* Copyright 2003-2008 The Apache Software Foundation. * * 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. * */
import java.io.InputStream; /**
* * @author * @version $Id: ClassUtils.java 685685 2008-08-13 21:43:27Z nbubna $ * @since 1.5 */
public class Main {
/**
* Finds a resource with the given name. Checks the Thread Context
* classloader, then uses the System classloader. Should replace all
* calls to Class.getResourceAsString
when the resource
* might come from a different classloader. (e.g. a webapp).
* @param claz Class to use when getting the System classloader (used if no Thread
* Context classloader available or fails to get resource).
* @param name name of the resource
* @return InputStream for the resource.
*/
public static InputStream getResourceAsStream(Class claz, String name)
{
InputStream result = null;
/**
* remove leading slash so path will work with classes in a JAR file
*/
while (name.startsWith("/"))
{
name = name.substring(1);
}
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
if (classLoader == null)
{
classLoader = claz.getClassLoader();
result = classLoader.getResourceAsStream( name );
}
else
{
result= classLoader.getResourceAsStream( name );
/**
* for compatibility with texen / ant tasks, fall back to
* old method when resource is not found.
*/
if (result == null)
{
classLoader = claz.getClassLoader();
if (classLoader != null)
result = classLoader.getResourceAsStream( name );
}
}
return result;
}
}
</source>
Listing all threads and threadgroups in the VM.
<source lang="java">
public class ThreadLister {
private static void printThreadInfo(Thread t, String indent) { if (t == null) return; System.out.println(indent + "Thread: " + t.getName() + " Priority: " + t.getPriority() + (t.isDaemon() ? " Daemon" : "") + (t.isAlive() ? "" : " Not Alive")); } /** Display info about a thread group */ private static void printGroupInfo(ThreadGroup g, String indent) { if (g == null) return; int numThreads = g.activeCount(); int numGroups = g.activeGroupCount(); Thread[] threads = new Thread[numThreads]; ThreadGroup[] groups = new ThreadGroup[numGroups]; g.enumerate(threads, false); g.enumerate(groups, false); System.out.println(indent + "Thread Group: " + g.getName() + " Max Priority: " + g.getMaxPriority() + (g.isDaemon() ? " Daemon" : "")); for (int i = 0; i < numThreads; i++) printThreadInfo(threads[i], indent + " "); for (int i = 0; i < numGroups; i++) printGroupInfo(groups[i], indent + " "); } /** Find the root thread group and list it recursively */ public static void listAllThreads() { ThreadGroup currentThreadGroup; ThreadGroup rootThreadGroup; ThreadGroup parent; // Get the current thread group currentThreadGroup = Thread.currentThread().getThreadGroup(); // Now go find the root thread group rootThreadGroup = currentThreadGroup; parent = rootThreadGroup.getParent(); while (parent != null) { rootThreadGroup = parent; parent = parent.getParent(); } printGroupInfo(rootThreadGroup, ""); } public static void main(String[] args) { ThreadLister.listAllThreads(); }
}
</source>
Return a new instance of the given class. Checks the ThreadContext classloader first, then uses the System classloader.
<source lang="java">
/*
* Copyright 2003-2008 The Apache Software Foundation. * * 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. * */
import java.io.InputStream; /**
* * @author * @version $Id: ClassUtils.java 685685 2008-08-13 21:43:27Z nbubna $ * @since 1.5 */
public class Main {
/** * Return a new instance of the given class. Checks the ThreadContext * classloader first, then uses the System classloader. Should replace all * calls toClass.forName( claz ).newInstance()
(which only * calls the System class loader) when the class might be in a different * classloader (e.g. in a webapp). * * @param clazz the name of the class to instantiate * @return an instance of the specified class * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException */ public static Object getNewInstance(String clazz) throws ClassNotFoundException,IllegalAccessException,InstantiationException { return getClass(clazz).newInstance(); } /** * Return the specified class. Checks the ThreadContext classloader first, * then uses the System classloader. Should replace all calls to *Class.forName( claz )
(which only calls the System class * loader) when the class might be in a different classloader (e.g. in a * webapp). * * @param clazz the name of the class to instantiate * @return the requested Class object * @throws ClassNotFoundException */ public static Class getClass(String clazz) throws ClassNotFoundException { /** * Use the Thread context classloader if possible */ ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) { try { return Class.forName(clazz, true, loader); } catch (ClassNotFoundException E) { /** * If not found with ThreadContext loader, fall thru to * try System classloader below (works around bug in ant). */ } } /** * Thread context classloader isn"t working out, so use system loader. */ return Class.forName(clazz); }
}
</source>
Sleep utilities
<source lang="java">
public final class TimerUtil {
public final static void wait(int waitTime) { try { Thread.sleep(waitTime); } catch (Exception e) {} } public final static void waitRandom(int time) { int waitTime = (int)(Math.random() * (double)time); try { Thread.sleep(waitTime); } catch (Exception e) {} }
}
</source>
Thread-based logging utility
<source lang="java">
/*
* Copyright Aduna (http://www.aduna-software.ru/) (c) 1997-2006. * * Licensed under the Aduna BSD-style license. */
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; /**
* Thread-based logging utility. The ThreadLog requires threads to register * themselves with the ThreadLog. In this registration procedure, a mapping is * made between the thread calling the registration method and an instance of * ThreadLog. This mapping is later used in all calls to logging-methods to * look-up whether these messages should be logged, and where they should be * logged.*
* Log messages are assigned a "level of importance". From high to low, these * levels are ERROR, WARNING, STATUS and TRACE. Messages can be suppressed based * on these levels. If a Thread registers itself with log level WARNING, only * errors and warning will be logged; status messages and traces will be * suppressed. */ public class ThreadLog { /*-----------* * Constants * *-----------*/ public static final int NONE = 0; public static final int ERROR = 1; public static final int WARNING = 2; public static final int STATUS = 3; public static final int TRACE = 4; public static final int ALL = 5; private static final String LINE_SEPARATOR = System.getProperty("line.separator"); /*------------------* * Static variables * *------------------*/ static SimpleDateFormat _formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); static String[] _levelNames = { "NONE ", "ERROR ", "WARNING", "STATUS ", "TRACE ", "ALL " }; /** Keeps track of which Threads maps to which ThreadLogs. */ static InheritableThreadLocal<ThreadLog> _threadContext = new InheritableThreadLocal<ThreadLog>(); static ThreadLog _defaultThreadLog; /** Maps (absolute) file paths to PrintWriters. */ static HashMap<String, Writer> _writerTable = new HashMap<String, Writer>(); /** * set the ThreadLog to log warning and error messages to System.err by * default */ static { setDefaultLog(null, WARNING); } /*----------------* * Static methods * *----------------*/ /** * Sets a default log file for all threads that have not registered * themselves. Logging calls from any of these threads to ThreadLog will be * logged to the specified log file if their priority is equal to or higher * then the specified log level. If "logFile" is equal to "null", messages * will be printed to System.err. * * @param logFile * The file to log to, or null to log messages to * System.err. * @param logLevel * One of the constants ERROR, WARNING, STATUS, TRACE, or ALL. * @see #ERROR * @see #WARNING * @see #STATUS * @see #TRACE * @see #ALL */ public static void setDefaultLog(String logFile, int logLevel) { if (_defaultThreadLog == null) { _defaultThreadLog = new ThreadLog(); } Writer logWriter = null; try { logWriter = _getLogWriter(logFile); } catch (IOException e) { System.err.println(e.getMessage()); e.printStackTrace(); try { logWriter = _getLogWriter(null); } catch (IOException ignore) { // ignore } } _defaultThreadLog.setLogWriter(logWriter); _defaultThreadLog.setLogLev(logLevel); } /** * Unsets the default log file for all threads that have not registered * themselves. */ public static void unsetDefaultLog() { _defaultThreadLog = null; } public static int getDefaultLogLevel() { if (_defaultThreadLog == null) { _defaultThreadLog = new ThreadLog(); } return _defaultThreadLog.getLogLev(); } /** * Registers the calling thread with the ThreadLog. Logging calls to * ThreadLog will be logged to the specified log file if their priority is * equal to or higher then the specified log level. If "logFile" is equal to * "null", messages will be printed to System.err. * * @param logFile * The file to log to, or null to log messages to * System.err. * @param logLevel * One of the constants ERROR, WARNING, STATUS, TRACE, or ALL. * @see #ERROR * @see #WARNING * @see #STATUS * @see #TRACE * @see #ALL */ public static void registerThread(String logFile, int logLevel) { ThreadLog threadLog = _createThreadLog(); Writer logWriter = null; try { logWriter = _getLogWriter(logFile); } catch (IOException e) { System.err.println(e.getMessage()); e.printStackTrace(); try { logWriter = _getLogWriter(null); } catch (IOException ignore) { // ignore } } threadLog.setLogWriter(logWriter); threadLog.setLogLev(logLevel); Thread currentThread = Thread.currentThread(); threadLog.setThreadName(currentThread.getName()); } /** * Changes the log level for the calling thread. * * @param logLevel * One of the constants ERROR, WARNING, STATUS, TRACE, or ALL. * @see #ERROR * @see #WARNING * @see #STATUS * @see #TRACE */ public static void setLogLevel(int logLevel) { ThreadLog threadLog = null; synchronized (_threadContext) { threadLog = _threadContext.get(); } if (threadLog != null) { threadLog.setLogLev(logLevel); } } public static int getLogLevel() { ThreadLog threadLog = _getThreadLog(); if (threadLog != null) { return threadLog._logLevel; } else { return NONE; } } public static boolean logLevelEnabled(int logLevel) { return getLogLevel() >= logLevel; } /** * Creates a ThreadLog for the thread calling this method. If the thread has * already created a ThreadLog before, this existing ThreadLog will be * returned. */ static ThreadLog _createThreadLog() { ThreadLog threadLog = null; synchronized (_threadContext) { threadLog = _threadContext.get(); if (threadLog == null) { threadLog = new ThreadLog(); _threadContext.set(threadLog); } } return threadLog; } /** * Gets a (possibly shared) Writer to the specified logFile. */ static Writer _getLogWriter(String logFile) throws IOException { Writer logWriter = null; String absPath = null; File file = null; if (logFile != null) { file = new File(logFile); absPath = file.getAbsolutePath(); } synchronized (_writerTable) { logWriter = _writerTable.get(absPath); if (logWriter == null) { // Create a new log writer if (absPath != null) { // Check if parent directory exists yet if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } logWriter = new FileWriter(absPath, true); } else { logWriter = new OutputStreamWriter(System.err); } _writerTable.put(absPath, logWriter); } } return logWriter; } /** * Deregisters the calling thread with the ThreadLog. Logging calls to * ThreadLog on the calling thread will no longer be logged. */ public static void deregisterThread() { synchronized (_threadContext) { _threadContext.set(null); } } /** * Gets the ThreadLog for the thread calling this method. If no ThreadLog is * available, null will be returned. */ static ThreadLog _getThreadLog() { ThreadLog threadLog = null; synchronized (_threadContext) { threadLog = _threadContext.get(); } if (threadLog == null) { threadLog = _defaultThreadLog; } return threadLog; } /*-----------* * Variables * *-----------*/ /** Writer for the log file. */ Writer _logWriter; /** Log level */ int _logLevel; /** * Name of the thread. */ String _threadName; /*--------------* * Constructors * *--------------*/ ThreadLog() { this(null, ALL); } ThreadLog(Writer logWriter) { this(logWriter, ALL); } ThreadLog(Writer logWriter, int logLevel) { setLogWriter(logWriter); setLogLev(logLevel); _threadName = null; } /*---------* * Methods * *---------*/ void setLogWriter(Writer logWriter) { _logWriter = logWriter; } void setLogLev(int logLevel) { _logLevel = logLevel; } int getLogLev() { return _logLevel; } void setThreadName(String threadName) { _threadName = threadName; } String getThreadName() { return _threadName; } void doLog(String msg, Object arg, int level) { // First check log level if (_logLevel < level) { return; } // Create log message String logMsg = _createLogMessage(msg, arg, level, _threadName); // Write log message // Synchronize on _logWriter to prevent mixed lines try { synchronized (_logWriter) { _logWriter.write(logMsg); _logWriter.flush(); } } catch (Exception e) { e.printStackTrace(); } } static String _createLogMessage(String msg, Object arg, int level, String threadName) { StringBuilder logMsg = new StringBuilder(128); logMsg.append(_formatter.format(new Date())); if (threadName != null) { logMsg.append(" ["); logMsg.append(threadName); logMsg.append("]"); } logMsg.append(" ["); logMsg.append(_levelNames[level]); logMsg.append("] "); logMsg.append(msg); if (arg != null) { logMsg.append(": "); if (arg instanceof Throwable) { Throwable throwable = (Throwable)arg; logMsg.append(throwable.getMessage()); logMsg.append(LINE_SEPARATOR); java.io.StringWriter stackTrace = new java.io.StringWriter(); java.io.PrintWriter pw = new java.io.PrintWriter(stackTrace); throwable.printStackTrace(pw); logMsg.append(stackTrace.toString()); } else { String argString = arg.toString(); if (argString.contains("\n") || argString.contains("\r")) { // argument formatted with newlines, do not append on same line logMsg.append(LINE_SEPARATOR); } logMsg.append(argString); } } logMsg.append(LINE_SEPARATOR); return logMsg.toString(); } /*------------------------* * Static utility methods * *------------------------*/ /** * Logs an error. * * @param msg * A indicative message for the error. */ public static void error(String msg) { _log(msg, null, ERROR); } /** * Logs an error. * * @param msg * A indicative message for the error. * @param arg * An argument related to the error. In case arg is an * instance of java.lang.Throwable, the message and stack * trace of the argument will be logged. */ public static void error(String msg, Object arg) { _log(msg, arg, ERROR); } /** * Logs a warning. * * @param msg * A indicative message for the warning. */ public static void warning(String msg) { _log(msg, null, WARNING); } /** * Logs a warning. * * @param msg * A indicative message for the warning. * @param arg * An argument related to the warning. In case arg is an * instance of java.lang.Throwable, the message and stack * trace of the argument will be logged. */ public static void warning(String msg, Object arg) { _log(msg, arg, WARNING); } /** * Logs a message. * * @param msg * A indicative message for the message. */ public static void log(String msg) { _log(msg, null, STATUS); } /** * Logs a message. * * @param msg * A indicative message for the message. * @param arg * An argument related to the message. In case arg is an * instance of java.lang.Throwable, the message and stack * trace of the argument will be logged. */ public static void log(String msg, Object arg) { _log(msg, arg, STATUS); } /** * Logs a trace message. * * @param msg * A indicative message for the trace message. */ public static void trace(String msg) { _log(msg, null, TRACE); } /** * Logs a trace message. * * @param msg * A indicative message for the trace message. * @param arg * An argument related to the trace message. In case arg is * an instance of java.lang.Throwable, the message and * stack trace of the argument will be logged. */ public static void trace(String msg, Object arg) { _log(msg, arg, TRACE); } /** * Logs a message on the specified level. * * @param msg * A indicative message for the trace message. * @param arg * An argument related to the trace message. In case arg is * an instance of java.lang.Throwable, the message and * stack trace of the argument will be logged. * @param level * One of the constants ERROR, WARNING, STATUS, TRACE, or ALL. * @see #ERROR * @see #WARNING * @see #STATUS * @see #TRACE * @see #ALL */ protected static void _log(String msg, Object arg, int level) { ThreadLog threadLog = _getThreadLog(); if (threadLog != null) { threadLog.doLog(msg, arg, level); } } } </source>
Transition Detector
<source lang="java">
public class TransitionDetectorMain extends Object {
private static Thread startTrueWaiter(final TransitionDetector td, String name) { Runnable r = new Runnable() { public void run() { try { while (true) { print("about to wait for false-to-" + "true transition, td=" + td); td.waitForFalseToTrueTransition(); print("just noticed for false-to-" + "true transition, td=" + td); } } catch (InterruptedException ix) { return; } } }; Thread t = new Thread(r, name); t.start(); return t; } private static Thread startFalseWaiter(final TransitionDetector td, String name) { Runnable r = new Runnable() { public void run() { try { while (true) { print("about to wait for true-to-" + "false transition, td=" + td); td.waitForTrueToFalseTransition(); print("just noticed for true-to-" + "false transition, td=" + td); } } catch (InterruptedException ix) { return; } } }; Thread t = new Thread(r, name); t.start(); return t; } private static void print(String msg) { String name = Thread.currentThread().getName(); System.err.println(name + ": " + msg); } public static void main(String[] args) { try { TransitionDetector td = new TransitionDetector(false); Thread threadA = startTrueWaiter(td, "threadA"); Thread threadB = startFalseWaiter(td, "threadB"); Thread.sleep(200); print("td=" + td + ", about to set to "false""); td.setValue(false); Thread.sleep(200); print("td=" + td + ", about to set to "true""); td.setValue(true); Thread.sleep(200); print("td=" + td + ", about to pulse value"); td.pulseValue(); Thread.sleep(200); threadA.interrupt(); threadB.interrupt(); } catch (InterruptedException x) { x.printStackTrace(); } }
} class TransitionDetector extends Object {
private boolean value; private Object valueLock; private Object falseToTrueLock; private Object trueToFalseLock; public TransitionDetector(boolean initialValue) { value = initialValue; valueLock = new Object(); falseToTrueLock = new Object(); trueToFalseLock = new Object(); } public void setValue(boolean newValue) { synchronized (valueLock) { if (newValue != value) { value = newValue; if (value) { notifyFalseToTrueWaiters(); } else { notifyTrueToFalseWaiters(); } } } } public void pulseValue() { // Sync on valueLock to be sure that no other threads // get into setValue() between these two setValue() // calls. synchronized (valueLock) { setValue(!value); setValue(!value); } } public boolean isTrue() { synchronized (valueLock) { return value; } } public void waitForFalseToTrueTransition() throws InterruptedException { synchronized (falseToTrueLock) { falseToTrueLock.wait(); } } private void notifyFalseToTrueWaiters() { synchronized (falseToTrueLock) { falseToTrueLock.notifyAll(); } } public void waitForTrueToFalseTransition() throws InterruptedException { synchronized (trueToFalseLock) { trueToFalseLock.wait(); } } private void notifyTrueToFalseWaiters() { synchronized (trueToFalseLock) { trueToFalseLock.notifyAll(); } } public String toString() { return String.valueOf(isTrue()); }
}
</source>
View current Threads in a table
<source lang="java">
import java.awt.BorderLayout; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.lang.reflect.InvocationTargetException; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; public class ThreadViewer extends JPanel {
private ThreadViewerTableModel tableModel = new ThreadViewerTableModel(); public ThreadViewer() { JTable table = new JTable(tableModel); table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); TableColumnModel colModel = table.getColumnModel(); int numColumns = colModel.getColumnCount(); for (int i = 0; i < numColumns - 1; i++) { TableColumn col = colModel.getColumn(i); col.sizeWidthToFit(); col.setPreferredWidth(col.getWidth() + 5); col.setMaxWidth(col.getWidth() + 5); } JScrollPane sp = new JScrollPane(table); setLayout(new BorderLayout()); add(sp, BorderLayout.CENTER); } public void dispose() { tableModel.stopRequest(); } protected void finalize() throws Throwable { dispose(); }
public static void main(String[] args) { JFrame f = new JFrame(); ThreadViewer viewer = new ThreadViewer(); f.setContentPane(viewer); f.setSize(500, 300); f.setVisible(true); f.setDefaultCloseOperation(1); // Keep the main thread from exiting by blocking // on wait() for a notification that never comes. Object lock = new Object(); synchronized (lock) { try { lock.wait(); } catch (InterruptedException x) { } } }
} class ThreadViewerTableModel extends AbstractTableModel {
private Object dataLock; private int rowCount; private Object[][] cellData; private Object[][] pendingCellData; private final int columnCount; private final String[] columnName; private final Class[] columnClass; private Thread internalThread; private volatile boolean noStopRequested; public ThreadViewerTableModel() { rowCount = 0; cellData = new Object[0][0]; String[] names = { "Priority", "Alive", "Daemon", "Interrupted", "ThreadGroup", "Thread Name" }; columnName = names; Class[] classes = { Integer.class, Boolean.class, Boolean.class, Boolean.class, String.class, String.class }; columnClass = classes; columnCount = columnName.length; dataLock = new Object(); noStopRequested = true; Runnable r = new Runnable() { public void run() { try { runWork(); } catch (Exception x) { // in case ANY exception slips through x.printStackTrace(); } } }; internalThread = new Thread(r, "ThreadViewer"); internalThread.setPriority(Thread.MAX_PRIORITY - 2); internalThread.setDaemon(true); internalThread.start(); } private void runWork() { Runnable transferPending = new Runnable() { public void run() { transferPendingCellData(); fireTableDataChanged(); } }; while (noStopRequested) { try { createPendingCellData(); SwingUtilities.invokeAndWait(transferPending); Thread.sleep(5000); } catch (InvocationTargetException tx) { tx.printStackTrace(); stopRequest(); } catch (InterruptedException x) { Thread.currentThread().interrupt(); } } } public void stopRequest() { noStopRequested = false; internalThread.interrupt(); } public boolean isAlive() { return internalThread.isAlive(); } private void createPendingCellData() { Thread[] thread = findAllThreads(); Object[][] cell = new Object[thread.length][columnCount]; for (int i = 0; i < thread.length; i++) { Thread t = thread[i]; Object[] rowCell = cell[i]; rowCell[0] = new Integer(t.getPriority()); rowCell[1] = new Boolean(t.isAlive()); rowCell[2] = new Boolean(t.isDaemon()); rowCell[3] = new Boolean(t.isInterrupted()); rowCell[4] = t.getThreadGroup().getName(); rowCell[5] = t.getName(); } synchronized (dataLock) { pendingCellData = cell; } } private void transferPendingCellData() { synchronized (dataLock) { cellData = pendingCellData; rowCount = cellData.length; } } public int getRowCount() { return rowCount; } public Object getValueAt(int row, int col) { return cellData[row][col]; } public int getColumnCount() { return columnCount; } public Class getColumnClass(int columnIdx) { return columnClass[columnIdx]; } public String getColumnName(int columnIdx) { return columnName[columnIdx]; } public static Thread[] findAllThreads() { ThreadGroup group = Thread.currentThread().getThreadGroup(); ThreadGroup topGroup = group; while (group != null) { topGroup = group; group = group.getParent(); } int estimatedSize = topGroup.activeCount() * 2; Thread[] slackList = new Thread[estimatedSize]; int actualSize = topGroup.enumerate(slackList); Thread[] list = new Thread[actualSize]; System.arraycopy(slackList, 0, list, 0, actualSize); return list; }
}
</source>