如何检查线程是否死锁了?

产生死锁的四个必要条件

(1) 互斥条件:一个资源每次只能被一个进程(线程)使用。
(2) 请求与保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件 : 此进程(线程)已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件 : 多个进程(线程)之间形成一种头尾相接的循环等待资源关系。

可以使用 jstack或者pstack 和 gdb 工具对死锁程序进行分析。

pstack: 功能是打印输出此进程的堆栈信息。可以输出所有线程的调用关系栈

jstack:jstack是java虚拟机自带的一种堆栈跟踪工具,所以仅适用于java程序,功能跟pstack一样,但是更强大,可以提示哪个地方可能死锁了。

pstack和jstack判断死锁,都需要多执行几次命令,观察每次的输出结果,才能推测是否死锁了。

gdb

1 运行程序,设置能影响程序运行的参数和环境 ;

2 控制程序在指定的条件下停止运行;

3 当程序停止时,可以检查程序的状态;

4 当程序 crash 时,可以检查 core 文件;

5 可以修改程序的错误,并重新运行程序;

6 可以动态监视程序中变量的值;

7 可以单步执行代码,观察程序的运行状态。

线程死锁分析:

1. 连续多次执行 $pstack <PID>   其中PID是进程号

查看每个线程的函数调用关系的堆栈,观察每个线程当前的执行点是否在等待一个锁。

多次执行该命令,发现某些线程的当前执行点不变,总是在等待同一个锁,就可以怀疑是否死锁了。

如果怀疑哪些线程发生死锁了,可以采用gdb 进一步attach线程并进行分析。

2. 执行$gdb -p <PID>  或者  $gdb attach <PID>

(gdb) info thread

(gdb) thread <thread ID>

BTW:gdb的all-stop和non-stop模式 (GDBv7.0及之上版本支持)

默认都是all-stop,即在某线程的代码里设置了断点,触发断点时所有的线程都会中断。

non-stop是多线程调试的好帮手,某个线程里的断点触发了,其它线程还照常run,可以重现死锁的场景。

想打开non-stop,可以修改~/.gdbinit,添加如下三行:

set target-async 1
    set pagination off
    set non-stop on

或者在进入gdb以后,依次执行以上三行,可以临时开启non-stop,退出gdb后失效。(猜是这样,需要实验验证)

另外,如果多个线程走的一个代码块,停在了同一个断点上,例如只想让线程1和线程3继续,使用:

(gdb) thread apply 3 1 continue

BTW,判断热锁。热锁是指经常被打开关闭打开关闭的锁,由于多个线程对锁或者临界区的竞争造成的。

频繁的线程的上下文切换:从操作系统对线程的调度来看,当 线程在等待资源而阻塞的时候,操作系统会将之切换出来,放到等待的队列,当线程获得资源之后,调度算法会将这个线程切换进去,放到执行队列中。
    * 大量的系统调用:因为线程的上下文切换,以及热锁的竞争,或 者临界区的频繁的进出,都可能导致大量的系统调用。
    * 大部分 CPU开销用在 “系统态 ”:线程上下文切换,和系统调用,都会导致 CPU在 “系统态 ”运行,换而言之,虽然系统很忙碌,但是 CPU用在 “用户态 ”的比例较小,应用程序得不到充分的 CPU资源。  
    * 随着 CPU数目的增多,系统的性能反而下降。因为 CPU数目多,同 时运行的线程就越多,可能就会造成更频繁的线程上下文切换和系统态的 CPU开销,从而导致更糟糕的性能。

可以通过脚本来固定时间间隔调用pstack,和查看系统资源使用情况的命令,比如top,分别将输出打印到log文件里。

当然要每次执行命令都得打印时间戳。

分析log文件,可以大概推测出热锁所在的位置。可以通过优化热锁,来提升程序的性能,例如吞吐量、响应时间。

原文地址:https://www.cnblogs.com/ryn3316/p/9404698.html

时间: 2024-10-12 12:17:03

如何检查线程是否死锁了?的相关文章

java并发-线程饥饿死锁测试

线程饥饿死锁 <Java并发编程实践>中对线程饥饿死锁的解释是这样的:在使用线程池执行任务时,如果任务依赖于其他任务,那么就可能产生死锁问题.在单线程的Executor中,若果一个任务将另一个任务提交到同一个Executor,并且等待这个被提交的任务的结果,那么这必定会导致死锁.第一个任务在工作队列中,并等待第二个任务的结果:而第二个任务则处于等待队列中,等待第一个任务执行完成后被执行.这就是典型的线程饥饿死锁.即使是在多线程的Executor中,如果提交到Executor中的任务之间相互依赖

线程的死锁

今天本人给大家讲解一下多线程的死锁,如有不对的或者讲的不好的可以多多提出,我会进行相应的更改,先提前感谢提出意见的各位了!!! 线程死锁 什么是线程的死锁? 产生死锁的原因? 因为资源的竞争:线程中都是进行抢占CPU的时间片的执行权,所以开启多线程可以一次性进行多个功能的使用,可是现在因为锁对象A和锁对象B的执行时机以及顺序的的不一致,导致线程相互等待,有时候会出现死锁的现象. 预防死锁 保证我们请求的资源数据的顺序要一致即可 案例:出现死锁的案例 public class Demo01 { p

jdk线程的死锁

两个线程相互等着对方释放同步监听器:等着要对方的结果后才能继续执行就会发生死锁. 男对女说:你先嫁给我,我再给你买房子:女对男说:你先给我买房子,我再嫁给你. 多个线程同时锁住同一个监听对象. 在开发中要避免死锁. 死锁的例子: public class DeadLock { public static void main(String[] args) { Resource r1 = new Resource(); Resource r2 = new Resource(); // 每个线程都拥有

如何避免线程的死锁

1.Java多线程中的死锁 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不能正常运行.形象的说就是:一个宝藏需要两把钥匙来打开,同时间正好来了两个人,他们一人一把钥匙,但是双方都再等着对方能交出钥匙来打开宝藏,谁都没释放自己的那把钥匙.就这样这俩人一直僵持下去,直到开发人员发现这个局面. 导致死锁的根源在于不适当地运用"synchronized"关键词来管理线程对特定对象的访问."synchronized

python并发编程之线程(创建线程,锁(死锁现象,递归锁),GIL锁)

什么是线程 进程:资源分配单位 线程:cpu执行单位(实体),每一个py文件中就是一个进程,一个进程中至少有一个线程 线程的两种创建方式: 一 from multiprocessing import Process def f1(n): print(n,'号线程') if __name__ == '__main__': t1 = Thread(target=f1,args=(1,)) t1.start() print('主线程')  二 from threading import Thread

数据库以及线程发生死锁的原理及必要条件,如何避免死锁

产生死锁的原因主要是: (1) 因为系统资源不足. (2) 进程运行推进的顺序不合适. (3) 资源分配不当等. 产生死锁的四个必要条件: (1)互斥条件:一个资源每次只能被一个进程使用. (2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放. (3)不可剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺. (4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系. 避免死锁: 死锁的预防是通过破坏产生条件来阻止死锁的产生,但这种方法破坏了系统的并行性和并发性

java中多线程的线程同步死锁问题

/* *定义一个多线程 */ package com.thread; public class TicketThread2 implements Runnable { //定义1000张票 public static int ticket = 100; Object obj = new Object(); // public boolean flag = false; // public boolean exit = false; @Override public void run() { //

线程同步——死锁问题

1.问题 1.1  产生的原因 系统有两个线程在跑,每个线程有两个锁,当线程一用了锁1,这个时候jvm调用线程二用了锁2,这个时候线程二不能打开锁1,程序就一直停在这里了 1.2  具体问题 有两个人Aman和Bman去执行刺杀任务,看成两个线程,老板那里只有一把匕首,要刺杀的只有一个人.Aman拿到了匕首,准备去接刺杀任务,但是任务却被Bman接了.Aman没有接刺杀任务,不能刺杀.Bman没有匕首,不能完成刺杀 1.3  解决办法 推荐不要用嵌套synchronized 2.代码 1 pub

jconsole检查性能及死锁

set JAVA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port="9004" -Dcom.sun.management.jmxremote.authenticate="false" -Dcom.sun.management.jmxremote.ssl="false" 9004为远程端口号 使用操作:在cmd中输入jconsole.exe,出现