/**
* ICE Futures, US
*/
package org.helios.apmrouter.util;
import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* <p>Title: ThreadUtils</p>
* <p>Description: Thread utility methods</p>
* <p>Company: ICE Futures US</p>
* @author Whitehead (nicholas.whitehead@theice.com)
* @version $LastChangedRevision$
* <p><code>org.helios.apmrouter.util.ThreadUtils</code></p>
*/
public class ThreadUtils {
/**
* Watches a thread and collects instances of Locks the thread waits on
* @param thread The thread to watch
* @param maxTime The maximum time to watch for
* @param unit The unit of the max time
* @param maxInfos The maximum number of infos to process
* @return the collected lock infos
*/
public static LockInfos trackLocksForThread(final Thread thread, final long maxTime, final TimeUnit unit, final int maxInfos) {
final LockInfos li = new LockInfos();
final ThreadMXBean threadMX = ManagementFactory.getThreadMXBean();
final long threadId = thread.getId();
final long end = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(maxTime, unit);
while(thread.isAlive()) {
if(System.currentTimeMillis() >= end || li.processed>=maxInfos) break;
ThreadInfo ti = threadMX.getThreadInfo(threadId);
if(ti!=null) {
li.addLockInfo(ti.getLockInfo());
}
}
System.err.println(li);
return li;
}
/**
* <p>Title: LockInfos</p>
* <p>Description: An accumulator of {@link LockInfo}s</p>
* <p>Company: ICE Futures US</p>
* @author Whitehead (nicholas.whitehead@theice.com)
* @version $LastChangedRevision$
* <p><code>org.helios.apmrouter.util.LockInfos</code></p>
*/
public static class LockInfos {
/** A map of lock infos keyed by the lock info's {@link LockInfo#getIdentityHashCode()} */
protected final Map<String, Integer> lockInfos = new HashMap<String, Integer>();
/** The number of lock infos processed */
protected int processed = 0;
/**
* Adds a lock info
* @param info the lock info to add
*/
public void addLockInfo(LockInfo info) {
if(info!=null) {
if(lockInfos.size()<128) {
if(!lockInfos.containsKey(info.toString())) {
lockInfos.put(info.toString(), 1);
} else {
lockInfos.put(info.toString(), lockInfos.get(info.toString())+1);
}
processed++;
}
}
}
public String toString() {
StringBuilder b = new StringBuilder("Thread LockInfo [");
for(Map.Entry<String, Integer> entry: lockInfos.entrySet()) {
b.append("\n\t").append(entry.getKey()).append(":").append(entry.getValue());
}
b.append("\n]");
return b.toString();
}
}
}