源于编程之美第一道题控制CPU,顺利用java把50%和sin线都画完之后(得把其他进程都关了,还得根据自己电脑核数创建相应线程数),该书提出C++直接监控当前windows系统的CPU占用率,动态的保持系统CPU占用率在50%。然后我就开始头疼了,没听说java这种跨平台的虚拟机上的语言有直接的接口查看操作系统的CPU信息啊,查找了各种资料。
- 一探,所谓的JAVA7添加的新功能,如果直接有接口那还不是太轻松了?果断试了一下,然后果断不行。。。
https://blog.csdn.net/jackyrongvip/article/details/6646358
写了如下代码进行测试:
package useRateOfCpu1_1;
import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;
public class Test{
public static void main(String[] args) {
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
// What % CPU load this current JVM is taking, from 0.0-1.0
System.out.println(osBean.getProcessCpuLoad());//指CPU的负载情况
while(true) {
System.out.println(osBean.getProcessCpuLoad());
if(osBean.getProcessCpuLoad() > 0.5) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
发现占有率一直是25%左右。。
查看官方文档:double getSystemCpuLoad() Returns the “recent cpu usage” for the whole system.
又在资源监视器里监视了运行后的进程,发现打印出的值跟该进程占的CPU相同,跟整个windows系统CPU占有率没啥关系。。。
-
二探,Sigar,开源工具肯定是第二个目标呀~
https://blog.csdn.net/HarderXin/article/details/76849884
https://github.com/hyperic/sigar
一个用C语言写的可供java调用的基本上能够获取操作系统的全部信息的包,刚找到的时候很兴奋,结果调了半天,最后eclipse给我报了一个JVM崩溃的错,google了半天,应该是java10或者win10版本兼容问题。。又不能用。。 -
三探,JNI,没办法了就看java提供了有什么能解决该问题的功能没 = 。=
这也就是今天的主题了,Java Native Interface,Java本地接口。JNI使得我们可以在JAVA中调用本地的C++代码(C++忘完了快),非常强大!
由于一些涉及到设备或底层操作的类库,大多是C或C++语言编写的,在涉及到相应的项目中,不可能再去将相应的类库用Java重写。这时,就需要通过Java代码去调用C/C++的类库来完成工作。
整个流程简单说就是:
写个java接口–>编译–>生成一个.h文件(java来生成的,所以jni才能用)–>根据.h文件把.cpp文件写出来,实现功能–>生成.dll动态链接库并放进classpath–>java文件调用接口完成功能
下面详细解释下各个部分,以及我踩的一些坑。
代码参考了 https://github.com/rootsu1024x/GetCPUMemNetOnJava
编写java接口
package net.caffeineswitch.lib.getcmn;
public class CPU {
static{
if("x86".equals(System.getProperty("os.arch"))){
System.loadLibrary("CPUUsage");
}else if("amd64".equals(System.getProperty("os.arch"))){
System.loadLibrary("TestJ");
}
}
public native double getCPUUsage();
public CPU() {
}
}
编写完成后javac编译成.class文件
生成.h头文件
这里很坑,查到的资料都让对上一步生成的.class文件利用jdk的javah命令来生成.h头文件。结果发现网上一些教程使用的方法(javah -jni 目标文件)已经过时,这是因为java10已经移除了javah的相关功能。
java10可以用来生成.h头文件
javac -h . CPU.java //注意h和C中间的“.”
生成的.h文件回事 包路径+类名
编写C++代码,生成dll文件
我为了图快直接VS2010写的,创建一个dll项目,注意要是x64平台的,这些坑大学期间踩过就明白有多烦人了,然后注意,要把你自己的jdk里的jni.h(jdk/include)和jni_md.h(jdk/include/win32),还有上面那个生成的.h文件都放进C++项目的头文件里,然后自己添加一个cpp文件,把功能实现了,这里就只是查看一下系统CPU,用的是windows自带的一个库,也是C++里自带的库Performance Data Helper (PDH),性能数据助手,可以根据 https://blog.csdn.net/fengyishang/article/details/46440135 一文把功能完成。这里就不细讲了。
之前没写过dll项目,编译的时候给我报错说不能运行,我以为一直有bug,结果查了下才发现自己太傻了,只生成个dll当然没有东西可以运行。去debug里一找,果然dll文件已经有了。
java链接进生成的dll文件
最简单的直接把dll放到jdk环境里面,然后就可以在java文件中使用了。
package net.caffeineswitch.lib.getcmn;
public class TestMain {
public static void main(String[] args) {
System.out.println(System.getProperty("os.arch"));
CPU cpu = new CPU();
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("CPU:"+cpu.getCPUUsage());
}
}
}
最后查了一下,跟任务管理器资源监视器里的CPU占用率还是有点不一样,不管怎么说,之前看到JNI、Sigar这些乱七八糟的词心里都慌慌的,觉得有好多东西要学,其实真的花了一个下午把这些没接触过的东西接触一遍,踩踩坑,发现其实也就是那么回事。
毕竟编程就是一个发现问题,找工具,解决问题的过程。