package com.yahoo.dtf.distribution;
import java.util.HashMap;
import java.util.Set;
import java.util.Map.Entry;
import com.yahoo.dtf.actions.protocol.CleanUpHook;
import com.yahoo.dtf.exception.DTFException;
import com.yahoo.dtf.logger.DTFLogger;
/**
* @dtf.feature Thread Management
* @dtf.feature.group Tag Development
* @dtf.feature.desc
* <p>
* Thread management within DTF is important so that DTF can correctly release
* agents whenever a DTFX (runner) disconnects during a test run. For this we
* have ThreadMgr class, which is able to register threads that can be
* interrupted if an agent is no longer being used and then there is an
* underlying utlility that can be used to detect the interruption and stop
* iterating.
* </p>
* <p>
* Remember that if you register a thread you should always unregister it when
* it has finished executing for good practice. Here is a small code example of
* how you should do such a thing in your own tag:
* </p>
* <pre>
* Thread t = new Thread() {
* public void run() {
* System.out.println("Do your thing!");
* }
* };
*
* t.start();
* ThreadMgr.registerThread(t);
* try {
* // do something else
* t.join();
* } finally {
* Threadmgr.unregisterThread(t);
* }
* </pre>
* <p>
* Very simple to use and it gaurantees that DTF can always clean up any of your
* threads even if your code does something bad or just fails to correctly clean
* up in certain instances. Any time that the Thread Manager has to clean up a
* thread because the agent is being released but the Thread is still registered
* under the ThreadMgr it will log to the screen a message like so on the agent
* side:
* </p>
* <pre>
* ThreadMgr - Interrupted [Thread-27,Thread-28,Thread-29]
* </pre>
* <p>
* Naming your threads according to your activity would make those thread names
* more meaningful and allow you to better understand whree they were registered.
* </p>
*
*/
public class ThreadMgr implements CleanUpHook {
private static DTFLogger _logger = DTFLogger.getLogger(ThreadMgr.class);
private static HashMap<String, Thread> _threads =
new HashMap<String, Thread>();
public static void registerThread(Thread t) {
synchronized (_threads) {
_threads.put(t.getName(), t);
}
}
public static void unregisterThread(Thread t) {
synchronized (_threads) {
_threads.remove(t.getName());
}
}
public void cleanup() throws DTFException {
synchronized (_threads) {
StringBuffer interrupted = new StringBuffer();
Set<Entry<String,Thread>> entries = _threads.entrySet();
for (Entry<String,Thread> entry : entries) {
Thread thread = entry.getValue();
thread.interrupt();
interrupted.append(thread.getName() + ",");
}
if ( interrupted.length() != 0 )
_logger.info("Interrupted [" + interrupted.toString() + "]");
}
}
}