public class ThreadCpuTest {
public static void main(String[] args) {
Executor executor = Executors.newFixedThreadPool(5);
executor.execute(() -> {
while (true) {
try {
TimeUnit.MICROSECONDS.sleep(200);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executor.execute(() -> {
while (true) {
try {
TimeUnit.MICROSECONDS.sleep(200);
System.out.println("hello world" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
就是开两个线程在疯狂刷
pom文件填加如下插件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
//指定main方法入口
<manifest>
<mainClass>com.test.ThreadCpuTest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
这个会在target下达成两个jar包,一个包含依赖,一个没有包含。用包含依赖那个
使用normalWork-1.0-SNAPSHOT-jar-with-dependencies.jar,但在这里jar包名称改为:normalWork-1.0-SNAPSHOT.jar(这块改写了,原先的打包方式没有打进依赖)。
FROM java:8
EXPOSE 8081
ADD normalWork-1.0-SNAPSHOT.jar work.jar
RUN sh -c ‘touch /work.jar’
ENV JAVA_OPTS="-Djava.rmi.server.hostname=$localName -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.rmi.port=1099 -Dcom.sun.management.jmxremote.ssl=false"
ENTRYPOINT [ “sh”, “-c”, “java $JAVA_OPTS -jar /work.jar” ]
JAVA_OPTS是用于开启JMX,进行jvm监控
ADD表示把文件拷入docker ,并改名成 work.jar
ENTRYPOINT 表示docker 启动执行第一个指令,这里是调用java 启动 jar
这里记录下RUN命令与CMD命令的区别:简单说,RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image文件;CMD命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令。
创建镜像命令:
docker build -t normalwork .
normalwork是镜像名称,该命令在Dockfile所在的目录执行,并且jar包和Dockerfile在一个目录(注意Dockfile里面内容),下图:
创建镜像成功如下:
这个时候执行docker images,可以发现已经有了
生成容器,容器生成后会自动运行java -jar work.jar,可以看出已经在打印输出了
docker run --env localName=192.168.0.106 -p 8081:8081 -p 1099:1099 -it --rm normalwork /bin/bash
(--env localName=192.168.0.106用于启动输入环境变量,这是是设置jmx的hostname)
第一步:
首先进入docker应用的虚拟环境:
docker exec -it 4b46751c85da /bin/bash
4b46751c85da是容器的containerid,通过docker ps直接查出
第二步:
查看所有运行中进程,获取想要的进程pid,在这里为6。
top
这里还有一种非常方便的方式获取jvm进程id,就是我们虚拟机自带的 jps 命令
jps 可以列出 正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称 以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)(进程ID)
在这里的效果如下:
第三步:
查看该进程下所有线程执行情况。
top -H -p 6 (-H表示展示线程)
可以发现pid为18、19的两个线程是cpu比较高得,也就是我们要找得。将18转为16进制:0x12,同理19:0x13。
第四步:
拉取jvm线程堆栈,6为上面的进程id。并cat 查看线程堆栈信息:
jstack -l 6 > temp.txt
cat temp.txt
通过上面的线程ID:0x12和0x13,去找对应的线程信息:
找到我们熟悉的代码,然后去具体看业务代码干了啥。
https://blog.csdn.net/xiao__gui/article/details/47341385
https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html
https://www.jianshu.com/p/2a32a4fc9852
https://blog.csdn.net/jiachengwin/article/details/73848952