死锁(DeadLock)是指两个或多个计算单元(进程、线程或协程),都在等待对方停止执行以获取系统资源,但没有一个提前退出,称为死锁。死锁示例下面我们来演示一下Java中最简单的死锁。我们创建两把锁和两个线程,让线程1先拥有锁A,1s后尝试获取锁B。同时启动线程2,先让它拥有锁B,1s后尝试获取锁A。这时候就会出现等待对方释放锁的情况,就会出现死锁问题。具体代码如下:publicclassDeadLockExample{publicstaticvoidmain(String[]args){ObjectlockA=newObject();对象锁B=新对象();Threadt1=newThread(newRunnable(){@Overridepublicvoidrun(){synchronized(lockA){System.out.println("Thread1:AcquiredlockA!");try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("Thread1:WaitingtoacquireB...");synchronized(lockB){System.out.println("Thread1:Acquired锁定B!");}}}});t1.开始();Threadt2=newThread(newRunnable(){@Overridepublicvoidrun(){synchronized(lockB){System.out.println("Thread2:ObtainedlockB!");try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("Thread2:WaitingtogetA..??.");synchronized(lockA){System.out.println("Thread2:Get锁定A!");}}}});t2.开始();}}上面程序的执行结果如下:从上面的结果可以看出,线程1和线程2都在等待对方释放锁,这就导致了通过上面的例子,我们可以得出结论:产生死锁需要满足以下四个条件:互斥条件:指计算单元(进程、线程或协程)分配的资源是独占的,即一个锁资源只能被其占用一段时间内一个计算单元。请求和保持条件:指操作单元至少保留了一个资源,但又提出新的资源请求,该资源已被其他操作单元占用。坚持,稍等。不可剥夺条件:指计算单元获得的资源,在用完之前不能被剥夺。循环等待条件:发生死锁时,必然存在计算单元和资源的循环链,即计算单元在等待另一个计算单元占用的资源,而另一方在等待自己占用的资源,导致循环等待案例。只有同时满足以上4个条件,才会出现死锁问题。死锁排查如果程序出现死锁问题,可以通过以下4种解决方案中的任意一种进行分析排查。方案一:jstack在我们使用jstack之前,我们需要通过jps获取到运行程序的进程ID。使用方法如下:“jps-l”可以查询本机所有Java程序。jps(JavaVirtualMachineProcessStatusTool)是一个Java提供的显示当前所有Java进程的pid的命令,适用于在linux/unix/windows平台上查看当前Java进程的一些简单情况,“-l”为用于输出进程pid和运行程序的全路径名(包名和类名)。我们有了进程ID(PID)之后,就可以通过“jstack-lPID”来查找死锁问题了,如下图所示:jstack用于生成Java虚拟机当前时刻的线程快照,“-l”表示长列表(long),打印关于锁的附加信息。PS:可以使用jstack-help查看更多命令说明。方案二:jconsole使用jconsole需要打开JDK的bin目录,找到jconsole双击打开,如下图:然后选择要调试的程序,如下图:然后点击连接进入,选择“不安全连接”进入监控首页,如下图:然后切换到“线程”模块,点击“检测死锁”按钮,如下图:过一会会检测到死锁的相关信息,如下图:解决方案三:jvisualvmjvisualvm也在JDK的bin目录下,同样是双击打开:几秒后,所有本地Java程序都会出现在jvisualvm中,如下图:双击选择要调试的程序:单机鼠标进入“线程”模块,如下图:从中可以看出上图,当我们切换到线程一栏时,死锁信息会直接显示出来,然后点击“ThreadDump”生成死锁的详细信息,如下图:解决方案4:jmcjmc是OracleJavaMissionControl的缩写,是一套管理、监控的工具、分析和故障排除Java程序。同样在JDK的bin目录下,同样是双击启动,如下图:jmc主页信息如下:选择要检查的程序后,右键“StartJMXConsole”可以查看程序的详细信息,如下图:然后点击“Thread”,勾选“DeadlockDetection”,可以找到死锁和死锁的详细信息,如下图:总结死锁是因为两个或者多个计算单元互相等待对方停止Execution获取系统资源,但是任何一方都没有提前退出,所以就出现了死锁。死锁排查工具有四种:jstackjconsolejvisualvmjmc考虑到易用性和性能,推荐使用jconsole或者jvisualvm排查死锁。
