性能测试三十七:线程死锁和阻塞

一、线程死锁

线程死锁就是有两个以上的线程,一个线程锁住了资源A,又想去锁定资源B,另外一个线程锁定了资源B,又想去锁定资源A,两个线程都想去得到对方的资源,而又不愿释放自己的资源
从而造成一种互相等待,无法执行的情况

接口:http://localhost:8080/PerfTeach/DeadServlet

因为要出现线程死锁至少要2个用户,所以用3个并发,永远跑

TPS:

响应时间

使用jstat -gcutil查看,JVM正常

使用dstat -tcdlmnsygr查看,cpu没什么压力

通过浏览器访问接口,没有响应

jvisualvm查看

jstack查看:使用jstack把堆栈日志打印到a.log里面

打开直接翻到最后,第8、4、7个线程出现死锁,并且会在下面把这三个线程拿出来打印

出现死锁的位置和原因:

所以是线程7锁定了资源,然后线程8和4在等待线程7解锁

看一下代码:出现了嵌套锁

现象:出现死锁后,tps降为0,压力测试工具无法得到服务器的响应,服务器硬件资源空闲,通过jvisualvm去查看线程情况,至少两个线程一直处于红色的阻塞状态
死锁经常表现为程序的停顿,或者不再响应用户的请求。从操作系统上观察,对应进程的CPU占用率为零

解锁办法:重启tomcat

定位方法:通过jvisualvm或者jstack,进行线程dump,对线程状态进行分析,获取到哪行代码导致的死锁,如:

Found one Java-level deadlock:
http-bio-8080"-exec-162":
waiting to lock monitor 0x0818abac (object 0x84b40ad0, a com.lee.domain.Order),
which is held by ""http-bio-8080"-exec-158"
""http-bio-8080"-exec-158":
waiting to lock monitor 0x08188cd0 (object 0x84b3bc48, a com.lee.domain.Order),
which is held by ""http-bio-8080"-exec-162"

Java stack information for the threads listed above:

死锁一般解决思路:
1、避免嵌套加锁
2、减小锁粒度,锁越少越不容易发生死锁

二、线程阻塞

线程阻塞问题-log4j日志级别问题
接口:http://localhost:8080/PerfTeach/Block?userId=1

30个并发永远跑,dstat监控起来:dstat -tcdlmnsygr --disk-util

从资源上看,问题不大

TPS:550左右

响应时间:46左右

一般在项目中发现响应式时间长,监控一下线程

右上角Dump,多Dump几次,这里Dump3次,然后把3个快照里面的内容分别复制3个文本里面,直接ctrl+f搜BLOCKED

代码里面这一行在打印日志

log4j代码里面有锁

解决方案:

1、还是用log4j,但是把日志打印级别提高,在代码里面减少不必要的日志打印输出

2、换其他日志组件如:log4j2、logback

log4j.xml中设置的日志级别,程序会打印在此级别之上日志
Error、Warn、Info、debug,级别越低,日志越多

cd /home/apps/app-PerfTeach/PerfTeach/WEB-INF/classes/

vi log4j.xml

默认打印级别是debug,改为error

重启tomcat

还是30个并发,永远跑

看一下tomcat下的日志

cd /home/server/tomcat-PerfTeach01/bin/D\:/

tail -f output.log

全是error级别的

TPS:900左右

响应时间:40左右

和刚才相比,TPS和响应时间都有明显的提升,由于配置比较低,这里提升不明显,真实公司里面的配置,最少提升2--3倍

从线程监控看,阻塞情况减少很多了,这个阻塞情况是因为打印error的日志

线程问题排查流程:
1、做线程dump
2、在dump文件中搜索关键字"BLOCKED"、"TIME_WAITTING",查看每种状态的count数量
3、按照上述关键字搜索,查看跟本系统有关的业务代码堆栈信息

原文地址:https://www.cnblogs.com/malinalian/p/10583264.html

时间: 2024-07-30 17:08:34

性能测试三十七:线程死锁和阻塞的相关文章

python第三十七天,GIL全局解释器锁*****,线程池与进程池 同步异步,阻塞与非阻塞,异步回调

GIL全局解释器锁 1.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe

一起talk C栗子吧(第一百一十七回:C语言实例--线程死锁一)

各位看官们,大家好,上一回中咱们说的是线程同步之互斥量的例子,这一回咱们说的例子是:线程死锁.闲话休提,言归正转.让我们一起talk C栗子吧! 我们在前面章回中介绍互斥量相关的函数时提到过死锁,不过当时没有做详细的介绍,有些看官对死锁不明白.因此,我们在今天的章回中详细介绍死锁,并且使用线程来显示死锁. 死锁就是不同的程序在运行时因为某种原因发生了阻塞,进而导致程序不能正常运行.阻塞程序的原因通常都是由于程序没有正确使用临界资源. 我们举个日常生活中的例子来比喻死锁.我们把马路上行驶的汽车比作

一起talk C栗子吧(第一百一十九回:C语言实例--线程死锁三)

各位看官们.大家好,上一回中咱们说的是线程死锁的样例,这一回咱们继续说该样例.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,由于篇幅的原因我们在上一回仅仅介绍了死锁发生的第一种原因,今天我们将介绍死锁发生的另外一种原因,而且该原因中的伪代码转换为实际的C语言代码. 为了方便,我们使用前面章回中演示相互排斥量的代码,在该代码的基础上做一些小改动来演示死锁.代码例如以下: 首先定义两个相互排斥量,相互排斥量是全局变量.方便线程使用. #if MUTEX_ENABLE pthread_m

C#编程总结(三)线程同步

C#编程总结(三)线程同步 在应用程序中使用多个线程的一个好处是每个线程都可以异步执行.对于 Windows 应用程序,耗时的任务可以在后台执行,而使应用程序窗口和控件保持响应.对于服务器应用程序,多线程处理提供了用不同线程处理每个传入请求的能力.否则,在完全满足前一个请求之前,将无法处理每个新请求.然而,线程的异步特性意味着必须协调对资源(如文件句柄.网络连接和内存)的访问.否则,两个或更多的线程可能在同一时间访问相同的资源,而每个线程都不知道其他线程的操作. "如果觉得有用,请帮顶! 如果有

在Linux下线程死锁的四个条件

一.死锁的原因和必要条件 1.死锁的概念 一般情况下,如果同一个线程先后两次调用lock,在第一次调用时,由于锁已经被占,该线程会挂起等待别的线程释放锁,然而锁正是被自己占着的,该线程又被挂起,没有机会释放锁,因此,就永远处于挂起等待状态了,这叫做死锁(Deadlock).另种典型的死锁情形是这样:线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(

GCD中的线程死锁问题

GCD 确实好用 ,很强大,相比NSOpretion 无法提供 取消任务的功能. 如此强大的工具用不好可能会出现线程死锁. 如下代码: - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"=================4"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"=================5"); }); NSLog(@"===

GCD 之线程死锁

GCD 确实好用 ,很强大,相比NSOpretion 无法提供 取消任务的功能. 如此强大的工具用不好可能会出现线程死锁. 如下代码: - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"=================4"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"=================5"); }); NSLog(@"===

线程-死锁

有多个线程执行的程序中,某个线程t1需要锁住两个对象obj1和obj2才能完成任务,而线程t2也需要锁住这两个对象,t1首先锁住obj1,t2首先锁住obj2,t1需要等待t2将obj2的锁放开,而t2也需要等待t1将obj1放开才能执行完,此时便进入了死锁状态. 死锁演示程序如下: 1 public class TestDeadLock implements Runnable 2 { 3 public int flag = 1; 4 static Object o1 = new Object(