`监控java中每个线程的cpu使用情况?

问题描述 投票:0回答:7

我想问是否有一些简单的方法可以确定

cpu usage
中每个线程的
java
。谢谢

java multithreading cpu-usage
7个回答
25
投票

我相信JConsole存档链接)确实通过插件提供了此类信息

JConsole Thread CPU usage, after blogs.oracle.com/lmalventosa/resource/thread_cpu_usage.jpg

它使用 ThreadMXBean getThreadCpuTime() 函数。

类似的事情:

        long upTime = runtimeProxy.getUptime();
        List<Long> threadCpuTime = new ArrayList<Long>();
        for (int i = 0; i < threadIds.size(); i++) {
            long threadId = threadIds.get(i);
            if (threadId != -1) {
                threadCpuTime.add(threadProxy.getThreadCpuTime(threadId));
            } else {
                threadCpuTime.add(0L);
            }
        }
        int nCPUs = osProxy.getAvailableProcessors();
        List<Float> cpuUsageList = new ArrayList<Float>();
        if (prevUpTime > 0L && upTime > prevUpTime) {
            // elapsedTime is in ms
            long elapsedTime = upTime - prevUpTime;
            for (int i = 0; i < threadIds.size(); i++) {
                // elapsedCpu is in ns
                long elapsedCpu = threadCpuTime.get(i) - prevThreadCpuTime.get(i);
                // cpuUsage could go higher than 100% because elapsedTime
                // and elapsedCpu are not fetched simultaneously. Limit to
                // 99% to avoid Chart showing a scale from 0% to 200%.
                float cpuUsage = Math.min(99F, elapsedCpu / (elapsedTime * 1000000F * nCPUs));
                cpuUsageList.add(cpuUsage);
            }
        }

15
投票

通过使用java.lang.management.ThreadMXBean。如何获取ThreadMXBean:

 ThreadMXBean tmxb = ManagementFactory.getThreadMXBean();

然后您可以使用以下方法查询特定线程的消耗量:

 long cpuTime = tmxb.getThreadCpuTime(aThreadID);

希望有帮助。


7
投票

选项_1:代码级别

在您的业务逻辑代码中;在开头调用 start() API,在finally 块中调用 stop()。这样您就可以获得当前正在运行的线程执行逻辑的 CPU 时间。然后记录它。 参考.

class CPUTimer 
{
    private long _startTime = 0l;

    public void start ()
    {
        _startTime = getCpuTimeInMillis();
    }


    public long stop ()
    {
        long result = (getCpuTimeInMillis() - _startTime);
        _startTime = 0l;
        return result;
    }

    public boolean isRunning ()
    {
        return _startTime != 0l;
    }

    /** thread CPU time in milliseconds. */
    private long getCpuTimeInMillis ()
    {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        return bean.isCurrentThreadCpuTimeSupported() ? bean.getCurrentThreadCpuTime()/1000000: 0L;
    }
}

选项_2:使用插件监控级别(不支持 jvisualvm 的 AIX IBM 机器)

如果您认为现在添加代码有点延迟,那么您可以更喜欢带有插件支持的 JConsole。我关注了this文章。从该文章下载 topthreads jar 并运行

./jconsole -pluginpath topthreads-1.1.jar

Option_3:使用 TOP (shift H) + JSTACK 监控级别(支持 'Shif+H' 的 Unix 机器)

按照 this 教程进行操作,其中 top 命令将提供查找顶级 CPU 线程 (nid) 的选项。检查 jstack 输出文件中的 nid。


2
投票

尝试“TopThreads”JConsole 插件。请参阅 http://lsd.luminis.nl/top-threads-plugin-for-jconsole/


1
投票

虽然这取决于平台,但我相信您正在寻找的是 ThreadMXBean:http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/ThreadMXBean.html 。例如,您可以使用 getThreadUserTime 方法来获取您需要的内容。要检查您的平台是否支持 CPU 测量,您可以调用 isThreadCpuTimeSupported() 。


1
投票

事实上 ThreadMXBean 对象提供了您需要的功能(但是它可能无法在所有虚拟机上实现)。

在 JDK 1.5 中,有一个演示程序可以完全满足您的需要。它位于 demo/management 文件夹中,名为 JTop.java

不幸的是,Java6 中没有它。也许你可以用google找到或者下载JDK5。


0
投票

我对此的回答是朝着不同的方向。

一种非常强大和透明的方法,也是收集线程 CPU 统计数据的超级方法,不是让你的 java 程序在内部收集它,而是通过一种与编程语言无关的方法来完成它。

例如,在 Linux 中,您可以使用 TOP 命令,该命令具有收集针对单个 java 进程的 CPU 统计信息的选项。 如果您随后将 jstack 与监视每个线程的 CPU 利用率的进程并行使用,那么您将获得两全其美的效果: (a) 您通过 jstack 线程转储知道在给定时间点您的代码正在做什么。 但这只是图片的一部分。 这并不能告诉你谁真正在烧毁你的CPU,而只是告诉你正在发生什么。 例如,如果您的 CPU 被垃圾收集线程烧毁,您将永远不会从线程转储中知道这一点。

(b) 将时间戳与 linux TOP 等工具的时间戳配对。 您将 Linux 线程 ID 转换为十六进制十进制。 十六进制小数出现在我们的堆栈跟踪中。 就这样。

对于 Windows,我最近才发现如何做同样的事情。 这是参考: https://xkln.net/blog/analyzing-thread-cpu-utilization-with-processexplorer-powershell-and-wmi/

所以这里有一些可能对您有用的代码:

# use the command:
#     Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
# in order to be allowed to run the powerhsell script

# SEE Original script: https://xkln.net/blog/analyzing-thread-cpu-utilization-with-processexplorer-powershell-and-wmi/

# (a) Discover the process we want to be monitoring
$process = ( (Get-WmiObject win32_process -Filter "name like '%java%'") | Where-object  {$_.CommandLine -like "*power*"} )
$processId = $process.processId

# (b) define the folder where we want to write out our staticis 
$baseFolterForSamples="C:\dev\apps_standalone\powersheell_threadCpuUtilization\threadCpuSamples"

# (c) Definition of a function that loops forever collecting the thread id of a 

    process
    function Get-ThreadProcessorUtilization() {
    
        Param(
            [Parameter(Mandatory=$true)]
            [int]$ProcId,
            [int]$DurationMs = 2000
        )
    
        $StatsPrev=$null;
        $ThreadAge = @{L="ThreadAge";E={[Timespan]::FromMilliseconds($_.ElapsedTime).ToString("hh\:mm\:ss")}}
        $ProcUtilization = @{L="ProcUtilization";E={(([Math]::Round(($_.UserModeTime - ($StatsPrev | ? Handle -eq $_.Handle).UserModeTime)/($_.ElapsedTime - ($StatsPrev | ? Handle -eq $_.Handle).ElapsedTime)*100,2)).ToString() + "%")}}
        
        # Define dome helper loop variables
        $currentItrationNumber = 0
        $previousIterationDateTime = $null
        
        while ($true) {
            $Stopwatch =  [System.Diagnostics.Stopwatch]::StartNew(); 
            $Stats = Get-CimInstance Win32_Thread -filter "ProcessHandle = $ProcId" | Select ProcessHandle, Handle, UserModeTime, ElapsedTime | Sort-Object -Property UserModeTime -Descending; 
            
            # create some loop variables that we will use to define the file name into which we want to 
            $currentTirationDateTime = $(get-date -f yyyy-MM-dd'T'hh:mm:ss.fff)
            $currentItrationNumberLpadZeros = '{0:d6}' -f $currentItrationNumber
            $currentOutputFileName = "$baseFolterForSamples\ThreadCpuTime_PID_${ProcId}_ItrationNr_$currentItrationNumber.txt"
            
            
            if ($StatsPrev -ne $null) {
                # This is the slow statement that is collecting the stats
                $CurrStats = $Stats | Select-Object ProcessHandle, Handle, $ThreadAge, $ProcUtilization
                Clear-Host
                
                # Write the current statistics into an output file
                $fileHeaderStart = "START Current Itration:  $currentItrationNumber Time Interval Sampled: [$previousIterationDateTime until $currentTirationDateTime]: "
                $fileHeaderEnd = "END Current Itration:  $currentItrationNumber Time Interval Sampled: [$previousIterationDateTime until $currentTirationDateTime]: "
                Write-Output $fileHeaderStart | Out-File -Filepath $currentOutputFileName
                Write-Output $CurrStats | Format-Table -AutoSize | Out-File -Filepath $currentOutputFileName -Append 
                Write-Output $fileHeaderEnd | Out-File -Filepath $currentOutputFileName -Append
                
                # REM Explain what we have just done here:
                echo "Generated sample output file: $currentOutputFileName with stats for CPU thread utilization for time period: [$previousIterationDateTime until $currentTirationDateTime]"
            }
            $statsPrev=$stats
            $Stopwatch.Stop()
    
            # This value could be coming negative          
            # $sleepDuration = $DurationMs-($Stopwatch.ElapsedMilliseconds)
            $sleepDuration = $DurationMs-($Stopwatch.ElapsedMilliseconds)
            $sleepDuration = [Math]::Max($sleepDuration,0)
            [System.Threading.Thread]::Sleep( $sleepDuration )
            
            # update the counter of curernt iteration
            $currentItrationNumber =  $currentItrationNumber + 1
            $previousIterationDateTime = $currentTirationDateTime
        }
    }
    
    Get-ThreadProcessorUtilization -ProcId $processId

您将看到出现在文件夹中: C:\dev\pps_standalone\powersheell_threadCpuUtilization hreadCpuSamples

您看到的代码与参考中的代码并不完全相同: https://xkln.net/blog/analyzing-thread-cpu-utilization-with-processexplorer-powershell-and-wmi/

但是它已经足够接近了,你只需要阅读参考文献就可以理解它。

© www.soinside.com 2019 - 2024. All rights reserved.