import java.lang.management.ManagementFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

import com.sun.management.ThreadMXBean;

public class ThreadAllocatedBytesTest {

	public static void main(String[] args) throws Exception {
		ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
		oldImpl(threadMXBean);
		newImpl(threadMXBean);
	}

	private static void oldImpl(ThreadMXBean threadMXBean) throws InterruptedException {
		
		final int numThreads = 1;
		final CountDownLatch start = new CountDownLatch(1);
		final CountDownLatch finished = new CountDownLatch(numThreads);
		final int numOtherThreads = 500;
		CountDownLatch otherStart = new CountDownLatch(numOtherThreads);
		Semaphore otherFinished = new Semaphore(0);
		
		for (int i = 0; i < numOtherThreads; i++) {
			new Thread() {
				public void run() {
					otherStart.countDown();
					try {
						otherFinished.acquire();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
		}
		
		for (int i = 0; i < numThreads; i++) {
			Thread thread = new Thread() {
				public void run() {
					try {
						start.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					for (int r = 0; r < 10; r++) {
						final int numRuns = 1000000;
						long start = System.nanoTime();
						for (int i = 0; i < numRuns; i++) {
							threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId());
						}
						long duration = System.nanoTime() - start;
						System.out.println(duration / numRuns);
					}
					finished.countDown();
				}
			};
			thread.start();
		}
		
		otherStart.await();
		start.countDown();
		finished.await();
		otherFinished.release(numOtherThreads);
	}
	
	private static void newImpl(ThreadMXBean threadMXBean) throws InterruptedException {
		
		final int numThreads = 1;
		final CountDownLatch start = new CountDownLatch(1);
		final CountDownLatch finished = new CountDownLatch(numThreads);
		final int numOtherThreads = 500;
		CountDownLatch otherStart = new CountDownLatch(numOtherThreads);
		Semaphore otherFinished = new Semaphore(0);
		
		for (int i = 0; i < numOtherThreads; i++) {
			new Thread() {
				public void run() {
					otherStart.countDown();
					try {
						otherFinished.acquire();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
		}
		
		for (int i = 0; i < numThreads; i++) {
			Thread thread = new Thread() {
				public void run() {
					try {
						start.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					for (int r = 0; r < 10; r++) {
						final int numRuns = 1000000;
						long start = System.nanoTime();
						for (int i = 0; i < numRuns; i++) {
							threadMXBean.getCurrentThreadAllocatedBytes();
						}
						long duration = System.nanoTime() - start;
						System.out.println(duration / numRuns);
					}
					finished.countDown();
				}
			};
			thread.start();
		}
		
		otherStart.await();
		start.countDown();
		finished.await();
		otherFinished.release(numOtherThreads);
	}
	
}
