如何获取在JVM中运行的java程序(单线程或多线程)的CPU时间?



在这篇文章中,使用挂钟时间对任务进行计时是不正确的

"挂钟时间"是用户等待任务完成所经历的真实经过时间。在 Java 1.5 之前,测量挂钟时间是基准测试 Java 任务的传统(也是唯一)方法。

要测量挂钟时间,请在任务前后呼叫java.lang.System . currentTimeMillis()并取差额。 该方法以毫秒(千分之一秒)为单位返回时间。

挂钟时间受到系统上其他活动的强烈影响,例如后台进程、其他应用程序、磁盘或网络活动以及显示器更新。在某些系统(如 Windows)上,如果应用程序不在顶部,它将以较低的优先级运行并花费更长的时间。所有这些都可能会扭曲您的基准测试结果,除非您非常小心地使用卸载的系统并在大量测试中求平均值。

如果您对用户的体验感兴趣,那么使用挂钟时间并不一定是坏事。但是,很难获得一致的基准测试数字来揭示您自己的应用程序的问题。

如果我们使用getProcessCpuTime(),似乎我们测量了 JVM 的所有时间。

那么如何区分JVM内部线程(下图)和java程序线程(单线程或多线程),以便我可以测量真正的Java程序线程CPU时间呢?

enum ThreadType {   //  **intrinsic threads**
vm_thread,
cgc_thread,        // Concurrent GC thread
pgc_thread,        // Parallel GC thread
java_thread,       // Java, CodeCacheSweeper, JVMTIAgent and Service threads.
compiler_thread,
watcher_thread,
os_thread
};

在这篇文章中,main_thread似乎是一个线程。突变器线程是由 JVM 创建的吗?(src/share/vm/runtime/thread.cpp)

3191   // Attach the main thread to this os thread
3192   JavaThread* main_thread = new JavaThread();
3193   main_thread->set_thread_state(_thread_in_vm);
3194   // must do this before set_active_handles and initialize_thread_local_storage
3195   // Note: on solaris initialize_thread_local_storage() will (indirectly)
3196   // change the stack size recorded here to one based on the java thread
3197   // stacksize. This adjusted size is what is used to figure the placement
3198   // of the guard pages.
3199   main_thread->record_stack_base_and_size();
3200   main_thread->initialize_thread_local_storage();

如果 Java 程序是多线程的,就像下面的程序一样怎么办

// Java code for thread creation by implementing
// the Runnable Interface
class MultithreadingDemo implements Runnable
{
public void run()
{
try
{
// Displaying the thread that is running
System.out.println ("Thread " +
Thread.currentThread().getId() +
" is running");
}
catch (Exception e)
{
// Throwing an exception
System.out.println ("Exception is caught");
}
}
}
int n = 8; // Number of threads
for (int i=0; i<8; i++)
{
Thread object = new Thread(new MultithreadingDemo());
object.start();
}    

为什么 MXBean 只返回 1 个主线程?

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.ArrayDeque;
import java.util.LinkedList;
public class MultiThread {
/** Get CPU time in nanoseconds. */
public long getCpuTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadCpuTime( ) : 0L;
}
/** Get user time in nanoseconds. */
public long getUserTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadUserTime( ) : 0L;
}
public static void main(String[] args) {
// deque operation
//ArrayDeque<LinkedList<Integer>> deque = new ArrayDeque<LinkedList<Integer>>();
ArrayDeque<Byte[]> deque = new ArrayDeque<Byte[]>();
int objectSize = 1024;
int xxx = 0;
// expand old and young heap size
for(long i = 0; i < 1500; i++){
for(int j = 0; j < 300; j++){
deque.addLast(new Byte[objectSize]);
}
for(int m = 0; m < 65535; m++){
xxx += 1;
xxx -= 1;
}
for(int j = 0; j < 20; j++){
deque.removeLast();
}
}
for(long i = 0; i < 1500; i++){
for(int j = 0; j < 300; j++){
deque.addLast(new Byte[objectSize]);
}
for(int m = 0; m < 65535; m++){
xxx += 1;
xxx -= 1;
}
for(int j = 0; j < 300; j++){
deque.removeFirst();
}
}
int n = 8; // Number of threads
for (int i=0; i<8; i++)
{
Thread object = new Thread(new MultithreadingDemo());
object.start();
}
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
//don't need monitor and synchronizer info,only get thread and stack info。
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for (ThreadInfo threadInfo : threadInfos) {
String tName = threadInfo.getThreadName();
long tId = threadInfo.getThreadId();
System.out.println(tName + "," + tId);
}
}
}

为什么 MXBeans只返回 1 个主线程?

因为您使用的是测量调用getCurrentThreadCpuTime时调用(当前)线程的 CPU 周期的ThreadMXBean。它完全按照它在锡上所说的去做,如果您想测量在选择测量的特定线程上花费了多少 CPU 时间,同时排除其他线程,这将非常有用。它提供了您要求的粒度。

MultiThread

这甚至不能编译,你至少应该在提问时努力发布一些真实的代码。

最新更新