在使用多线程时,如果使用不当,就会产生一些问题,比如:
先创建一个应用,模拟一个死锁问题和cpu占用率过高的问题,核心代码如下:
/**
* 模拟一个死锁问题和cpu占用率过高的问题
*/
@RestController
public class ThreadController
{
@GetMapping("/loop")
public String dumpWhile()
{
new Thread(new WhileThread()).start();
return "OK";
}
@GetMapping("/dead")
public String dumpDeadlock()
{
Thread a = new ThreadRunA();
Thread b = new ThreadRunB();
a.start();
b.start();
return "OK";
}
}
class WhileThread implements Runnable{
@Override
public void run()
{
while (true)
{
System.out.println("Thread");
}
}
}
class ThreadRunA extends Thread{
@Override
public void run()
{
System.out.println("======================A====================");
synchronized (A.A){
System.out.println("我要开始执行任务A..."+Thread.currentThread().getName());
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
synchronized (B.B)
{
}
System.out.println("我在执行任务结束了A..."+Thread.currentThread().getName()+":"+B.B.hashCode()+":"+A.A.hashCode());
}
}
}
class ThreadRunB extends Thread{
@Override
public void run()
{
System.out.println("======================B====================");
synchronized (B.B){
System.out.println("我要开始执行任务B..."+Thread.currentThread().getName());
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
synchronized (A.A)
{
}
System.out.println("我在执行任务结束了B..."+Thread.currentThread().getName()+":"+B.B+":"+A.A);
}
}
}
死锁导致请求无法响应
将上面的这段运行程序,使用如下命令制造死锁现场:
curl :8080/dead
对于死锁问题的排查,具体操作步骤如下:
第一步,通过 jps 命令,查看Java进程的pid.
第二步,通过 命令查看线程dump日志.
当发现死锁时,可以在打印的dump日志中找到Found one Java-level : 信息,根据信息内容分析问题出现的原因.
是Java虚拟机自带的一种堆栈跟踪工具,它主要用于打印指定Java进行ID中当前时刻的线程dump日志,线程快照是当前Java虚拟机内每一条线程正在执行的方法堆栈的集合. 生成线程快照的主要目的是定位线程出现长时间停顿的原因, 如线程间死锁,死循环,请求外部的资源导致的长时间等待等,语法格式如下:
CPU占用率过高,响应很慢
为了演示CPU过高的场景,先执行如下的命令, 这个命令会让线程进入死循环状态.
curl :8080/loop
上述命令运行完之后,通过top -c 命令可以动态显示进程及其占用资源的排行榜,从结果可以找到占用CPU最高的进程PID.
可以看到,CPU占用率比较高 的PID是21602,定位到该进程之后,我们再从线程的dump日志中去定位.
21602 | grep -A 20 // pid(进程id) | grep 16进制线程 -A 行数
-A 表示显示匹配行及其后面的n行.
通过上述操作后,得到的线程dump信息如下,从该信息中我们发现,在.run()方法中因为某个操作导致cpu占用率高,于是基于这个信息我们可以进行分析从而解决该问题.
上述代码内容其实可以分为三个部分.
。 -2 表示线程名字,为了更好地辨别,建议大家在使用线程的时候自己进行命令.
。 #29,线程的编号。
。 ,表示守护线程。
。 prio,线程的优先级,Java 中的线程优先级分为 1~10 个级别,数字越高表示优先级高,优先级高的线程能够有更高的概率优先得 到 CPU 的执行。
。 ,表示操作系统层面的线程优先级,Java 中配置的线程优先级最终会映射到操系统中的线程优先级。
。 tid=,JM 内部线程 ID
。 nid,系统线程ID
。 ,线程状态
———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666