前言
CPU100%和线程死锁都是造成系统运行缓慢、假死的原因之一。这里讲解下如果发生这种情况如何定位。
CPU100%定位
CPU100%环境模拟
首先我们给出如下代码模拟出CPU100%
public static void main(String[] args) {
cpuTest();
}
private static void cpuTest() {
new Thread(() -> {
while (true) {
new Object();
}
}, "CPU-100").start();
while (true) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
new Object();
long random = new Random().nextInt(200);
Thread.sleep(random);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
复制代码
我们要模拟的场景是一个一直忙碌的死循环线程隐藏在众多线程之中。
程序逻辑:启动一个不断执行的死循环线程命名为CPU-100,另外主线程每隔200毫秒启动10个线程。
线程定位
执行top命令,找到java进程CPU总的使用率105.6%,进程id为22024
执行top -H -p 22024 查看该进程下所有线程的CPU使用率等情况。其中线程id为22041的CPU使用率99.9%。
执行jstack 22024 > stack.log,将该java进程的线程栈信息转储到stack.log
查看stack.log,可以查看当前线程信息,包括线程名、线程ID、方法、状态等。其中nid即是我们前面找的线程id,只不过它以16进制展示。22041转16进制是0x5619
我们搜索0x5619即可以定位到具体的线程,进而位到具体的程序代码线程死锁定位
jstack可以查看线程状态,所以也可以定位死锁问题。
死锁环境模拟
首先我们给出如下代码构造死锁,死锁线程分别命名为deadLock-1、deadLock-2
public static void main(String[] args) {
lockTest();
}
private static void lockTest() {
Object o1 = new Object();
Object o2 = new Object();
new Thread(() -> {
synchronized (o1) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println("deadLock-1");
}
}
},"deadLock-1").start();
new Thread(() -> {
synchronized (o2) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println("deadLock-2");
}
}
},"deadLock-2").start();
}
复制代码
线程定位
jcmd 找到进程id 41579
jstack 41579,发现deadLock-1,deadLock-2线程都处于阻塞状态,最下面会直接给出死锁信息