最近確實遇到題目上的剛需,也是花了一段時間來思考這個問題。java
計算使用率在上學那會就常常算,不過每每計算的是整個程序執行的時間段,如今忽然要實時計算還真有點無奈,時間段如何選擇是個問題。最後根據現有的程序作參考,那就是Linux的top命令源碼。linux
top命令仍是c程序,加之開源,我直接採起相同的時間段和計算方法。c++
先說說top是如何計算的,首先是從/proc/stat下讀取cpu的使用時間,其次就是/proc/pid/stat獲取進程的cpu時間,/proc/pid/task裏獲取這個進程裏每一個線程的id,而後繼續從stat裏查找cpu的使用時間。windows
線程cpu的利用率=線程運行的時間差(包括用戶態+核心態+。。。。)/cpu運行時間之差(用戶態+核心態+io+.....)api
每隔3秒查詢計算一次。jvm
既然要獲取cpu信息,我查詢了不少方法,最終肯定,java自己是作不到的(windows可沒有/proc這樣的文件給你查看),要藉助c/c++來處理,本來我調用函數都查好了,就差寫jni了,結果有人給我推薦了sigar。是就是基於本地庫實現的,不過他已經把本地庫這些都準備好了,基本每一個平臺都有,這樣提供了很大的方便。接下來就是對這個庫的使用過程了。函數
根據給出的參考例子和相關api文檔。咱們導入Jar包後須要繼承SigarCommandBase這個類,咱們一切的操做基本依靠父類的成員變量sigarthis
Cpu[] cpus = this.sigar.getCpuList();//獲取cpu信息 long time = 0L; for (int i = 0; i < cpus.length; i++) { time += cpus[i].getTotal(); } return time;
先獲取到cpu的信息,而後直接經過getTotal來獲得當前cpu的運行時間,你能夠用cpus獲取到cpu在覈心態運行時間等等,我最後嘗試加起來和getTotal小有出入,差異不大,因此採用getTotal就能夠了,這樣就能獲取cpu運行時間,第二次採集時也就知道時間差了。spa
接下來就是獲取java線程信息這些了,依然仍是算差值。線程
ThreadMXBean mx = ManagementFactory.getThreadMXBean(); long[] threadIds = mx.getAllThreadIds(); ThreadInfo[] threadInfos = mx.getThreadInfo(threadIds);
經過上面的代碼就能夠獲取到如今進程裏每一個線程的信息。
long time = mx.getThreadCpuTime(threadId);
再經過getThreadCpuTime方法根據tid來獲取到該線程在cpu上運行總時間,java文檔上是這麼寫的:返回指定 ID 的線程的總 CPU 時間(以毫微秒爲單位)。這裏的單位是毫微秒的單位,要注意轉換。
我保存線程信息是用一個map,主鍵是線程id,這裏你們就須要稍微注意一下,我更建議是線程id+線程名字的手段來作主鍵,tid是標識惟一一個線程,咱們假設a線程的id是34,若是a線程死掉以後,b線程啓動,jvm會不會把34號標識給b線程呢,這裏我不敢確定,我感受是會的。在linux的文件描述符也是惟一標識一個文件的,可是你一個文件關閉後,再開一個,確定會佔用到相同的描述符。因此我感受線程的id也是如此,id是標識了惟一的線程,可是線程死掉,從新分配的話,這樣也代碼沒必要要的困擾。
剩下的就是算差值來計算使用率了,記得把動態庫的位置加上,-Djava.library.path="位置",windows下能夠加到path路徑下,linux能夠指定LD_LIBARARY_PATH。