Java死锁示例–如何分析死锁情况

死锁是两个或多个线程永远被阻塞的编程情况,这种情况发生在至少两个线程和两个或更多资源的情况下。 在这里,我编写了一个简单的程序,该程序将导致死锁情况,然后我们将看到如何对其进行分析。

Java死锁示例

package com.journaldev.threads;
public class ThreadDeadlock {public static void main(String[] args) throws InterruptedException {Object obj1 = new Object();Object obj2 = new Object();Object obj3 = new Object();Thread t1 = new Thread(new SyncThread(obj1, obj2), 't1');Thread t2 = new Thread(new SyncThread(obj2, obj3), 't2');Thread t3 = new Thread(new SyncThread(obj3, obj1), 't3');t1.start();Thread.sleep(5000);t2.start();Thread.sleep(5000);t3.start();}
}
class SyncThread implements Runnable{private Object obj1;private Object obj2;public SyncThread(Object o1, Object o2){this.obj1=o1;this.obj2=o2;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + ' acquiring lock on '+obj1);synchronized (obj1) {System.out.println(name + ' acquired lock on '+obj1);work();System.out.println(name + ' acquiring lock on '+obj2);synchronized (obj2) {System.out.println(name + ' acquired lock on '+obj2);work();}System.out.println(name + ' released lock on '+obj2);}System.out.println(name + ' released lock on '+obj1);System.out.println(name + ' finished execution.');}private void work() {try {Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的程序中,SyncThread实现了Runnable接口,并且通过使用同步块逐个获取每个对象上的锁,从而对两个对象起作用。

在main方法中,我为SyncThread运行了三个线程,并且每个线程之间都有一个共享资源。 线程以这样的方式运行:它将能够获取第一个对象的锁定,但是当它试图获取第二个对象的锁定时,它将进入等待状态,因为它已经被另一个线程锁定了。 这对导致死锁的线程之间的资源形成了循环依赖性。

当我执行上面的程序时,这是生成的输出,但是由于死锁,程序永远不会终止。

t1 acquiring lock on java.lang.Object@6d9dd520
t1 acquired lock on java.lang.Object@6d9dd520
t2 acquiring lock on java.lang.Object@22aed3a5
t2 acquired lock on java.lang.Object@22aed3a5
t3 acquiring lock on java.lang.Object@218c2661
t3 acquired lock on java.lang.Object@218c2661
t1 acquiring lock on java.lang.Object@22aed3a5
t2 acquiring lock on java.lang.Object@218c2661
t3 acquiring lock on java.lang.Object@6d9dd520

在这里,我们可以从输出中清楚地确定死锁情况,但是在实际应用中,很难找到死锁情况并对其进行调试。

分析死锁

要分析死锁,我们需要查看应用程序的Java线程转储 ,在上一篇文章中,我解释了如何使用VisualVM Profiler或jstack实用程序生成线程转储 。

这是上面程序的线程转储。

2012-12-27 19:08:34
Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.5-b02 mixed mode):
'Attach Listener' daemon prio=5 tid=0x00007fb0a2814000 nid=0x4007 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'DestroyJavaVM' prio=5 tid=0x00007fb0a2801000 nid=0x1703 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
't3' prio=5 tid=0x00007fb0a204b000 nid=0x4d07 waiting for monitor entry [0x000000015d971000]java.lang.Thread.State: BLOCKED (on object monitor)at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f658> (a java.lang.Object)- locked <0x000000013df2f678> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't2' prio=5 tid=0x00007fb0a1073000 nid=0x4207 waiting for monitor entry [0x000000015d209000]java.lang.Thread.State: BLOCKED (on object monitor)at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f678> (a java.lang.Object)- locked <0x000000013df2f668> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't1' prio=5 tid=0x00007fb0a1072000 nid=0x5503 waiting for monitor entry [0x000000015d86e000]java.lang.Thread.State: BLOCKED (on object monitor)at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f668> (a java.lang.Object)- locked <0x000000013df2f658> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
'Service Thread' daemon prio=5 tid=0x00007fb0a1038000 nid=0x5303 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'C2 CompilerThread1' daemon prio=5 tid=0x00007fb0a1037000 nid=0x5203 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'C2 CompilerThread0' daemon prio=5 tid=0x00007fb0a1016000 nid=0x5103 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'Signal Dispatcher' daemon prio=5 tid=0x00007fb0a4003000 nid=0x5003 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'Finalizer' daemon prio=5 tid=0x00007fb0a4800000 nid=0x3f03 in Object.wait() [0x000000015d0c0000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000013de75798> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)- locked <0x000000013de75798> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)
'Reference Handler' daemon prio=5 tid=0x00007fb0a4002000 nid=0x3e03 in Object.wait() [0x000000015cfbd000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000013de75320> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:503)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)- locked <0x000000013de75320> (a java.lang.ref.Reference$Lock)
'VM Thread' prio=5 tid=0x00007fb0a2049800 nid=0x3d03 runnable
'GC task thread#0 (ParallelGC)' prio=5 tid=0x00007fb0a300d800 nid=0x3503 runnable
'GC task thread#1 (ParallelGC)' prio=5 tid=0x00007fb0a2001800 nid=0x3603 runnable
'GC task thread#2 (ParallelGC)' prio=5 tid=0x00007fb0a2003800 nid=0x3703 runnable
'GC task thread#3 (ParallelGC)' prio=5 tid=0x00007fb0a2004000 nid=0x3803 runnable
'GC task thread#4 (ParallelGC)' prio=5 tid=0x00007fb0a2005000 nid=0x3903 runnable
'GC task thread#5 (ParallelGC)' prio=5 tid=0x00007fb0a2005800 nid=0x3a03 runnable
'GC task thread#6 (ParallelGC)' prio=5 tid=0x00007fb0a2006000 nid=0x3b03 runnable
'GC task thread#7 (ParallelGC)' prio=5 tid=0x00007fb0a2006800 nid=0x3c03 runnable
'VM Periodic Task Thread' prio=5 tid=0x00007fb0a1015000 nid=0x5403 waiting on condition
JNI global references: 114
Found one Java-level deadlock:
=============================
't3':waiting to lock monitor 0x00007fb0a1074b08 (object 0x000000013df2f658, a java.lang.Object),which is held by 't1'
't1':waiting to lock monitor 0x00007fb0a1010f08 (object 0x000000013df2f668, a java.lang.Object),which is held by 't2'
't2':waiting to lock monitor 0x00007fb0a1012360 (object 0x000000013df2f678, a java.lang.Object),which is held by 't3'
Java stack information for the threads listed above:
===================================================
't3':at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f658> (a java.lang.Object)- locked <0x000000013df2f678> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't1':at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f668> (a java.lang.Object)- locked <0x000000013df2f658> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't2':at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f678> (a java.lang.Object)- locked <0x000000013df2f668> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
Found 1 deadlock.

线程转储输出清楚地显示了死锁情况,并且所涉及的线程和资源导致了死锁情况。

为了分析死锁,我们需要找出状态为BLOCKED的线程,然后寻找它正在等待锁定的资源,每个资源都有一个唯一的ID,通过它我们可以找到哪个线程已经在对象上保持了锁定。 例如,线程“ t3”正在等待锁定0x000000013df2f658,但它已被线程“ t1”锁定。

一旦我们分析了死锁情况并找出了导致死锁的线程,就需要进行代码更改以避免死锁情况。

避免死锁

这些是我们可以避免大多数僵局情况的一些准则。

  • 避免嵌套锁 :这是造成死锁的最常见原因,如果已经持有另一个资源,请避免锁定另一个资源。 如果仅使用一个对象锁,则几乎不可能出现死锁情况。 例如,这是不带嵌套锁的run()方法的另一种实现,并且程序成功运行且没有死锁情况。
    public void run() {String name = Thread.currentThread().getName();System.out.println(name + ' acquiring lock on ' + obj1);synchronized (obj1) {System.out.println(name + ' acquired lock on ' + obj1);work();}System.out.println(name + ' released lock on ' + obj1);System.out.println(name + ' acquiring lock on ' + obj2);synchronized (obj2) {System.out.println(name + ' acquired lock on ' + obj2);work();}System.out.println(name + ' released lock on ' + obj2);System.out.println(name + ' finished execution.');}
  • 仅锁定所需条件 :您应该仅对必须处理的资源获得锁定,例如,在上述程序中,我正在锁定完整的Object资源,但是如果我们仅对其中一个字段感兴趣,则应仅锁定该对象具体字段不完整的对象。
  • 避免无限期地等待 :如果两个线程正在使用线程连接无限期地等待彼此完成,则可能会陷入死锁。 如果您的线程必须等待另一个线程完成,则始终最好使用join,并在等待线程完成的最长时间内使用它。

参考: Java死锁示例–如何从开发人员食谱博客的JCG合作伙伴 Pankaj Kumar中分析死锁情况 。

翻译自: https://www.javacodegeeks.com/2013/01/java-deadlock-example-how-to-analyze-deadlock-situation.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目

不解的问题&#xff1a;表格里td能否用margin&#xff1f;覆盖z-index需要设置背景才能覆盖&#xff1f;表格与表格能否用float&#xff1f; 转载于:https://www.cnblogs.com/ssx5310518/p/7282199.html

Scude导入MySQL_FM2017_FMF赛季更新和真实修正数据库[更新至9.9,超过89000个更新]

FM2017_FMF赛季更新和真实修正数据库[更新至9.9&#xff0c;超过89000个更新]FM2017_FMF赛季更新和真实修正数据库[更新至9.9&#xff0c;超过89000个更新](2)这是国外玩家制作的一款FM2017_FMF冬季更新和真实修正数据库&#xff0c;更新至9月9日&#xff0c;超过89000个更新内…

音视频和表单的详情

网页中的音视频 <audio> 和 <vedio> 标签属性&#xff1a;autoplay 自动播放 controls 控制播放 loop 循环播放 表单 HTML 表单用于收集用户输入。 标签<form> 标签属性 action 数据的路径 enctype 传输文件 enctype"multipart/form-data" method …

使用Jackson和Super类型令牌进行Json反序列化

Datatables是一个jquery插件&#xff0c;用于显示表格信息–它可以增强简单的表或可以使用基于AJAX的数据并以表格形式显示信息。 数据表要​​求来自服务器的数据遵循特定的JSON格式才能在屏幕上显示。 考虑要显示成员实体列表的情况&#xff0c;那么对于成员而言&#xff0c…

马拉车

O(n)求字符串中的最长回文串的长度 1 char s[SIZE];2 int len[SIZE*2];3 char str[SIZE*2];4 int manacher(){//预处理字符串&#xff0c;将字符串隔开,且开头和结尾字符串要不同,防止越界&#xff0c;如aaa预处理为#a#a#a$5 int l strlen(s);6 int ls 0;7 st…

mysql otter 数据同步_MySQL数据同步之otter

一、otter介绍基于日志数据&#xff0c;用于MySQL或者ORACLE之间准实时同步数据。用途&#xff1a;mysql/oracle互相同步中间表/行记录同步二、原理及架构图otter整体模块manager (提供web页面进行同步管理)arbitrate (分布式调度&#xff0c;可跨IDC机房)node (同步过程setl)c…

ubuntu中获取文件名称并生成txt文件

简介&#xff1a; 在机器视觉学习过程中&#xff0c;通常会经常批量处理一些图片&#xff0c;在&#xff35;&#xff42;&#xff55;&#xff4e;&#xff54;&#xff55;下可以使用find命令&#xff0c;来实现将文件名全部读取出来&#xff0c;生成列表txt文件&#xff0c;…

使用Google Guava创建收藏和实现不变性

因此&#xff0c;我想看看番石榴提供的一些集合创建模式&#xff0c;以及它提供的某些不可变集合类型。 如果您没有看过我以前的文章&#xff0c;则可能要从这里开始&#xff1a; 番石榴第1部分– MultiMaps 番石榴第2部分– BiMaps 番石榴第3部分–多组 Guava的所有集合实…

HTMLCSS

HTML xml &#xff08;标签名&#xff09;可扩展标记语言 <Stu> </Stu> Html 超文本标记语言&#xff08;文本&#xff0c;图片&#xff0c;链接&#xff09; <> </> Internet网上编写页面&#xff08;H5版本&#xff1a;支持多种标签特性&…

Mysql报错130_mysql 突然报错,连接不上

错误如下&#xff0c; Access denied for user rootlocalhost (using password关掉mysql服务&#xff0c;重新启动如果不行&#xff0c;那应该就是密码被改了&#xff0c;密码不对应1.以系统管理员身份运行cmd.2.查看mysql是否已经启动&#xff0c;如果已经启动&#xff0c;就停…

为内存密集型应用程序转义JVM堆

如果您曾经分配过大的Java堆&#xff0c;您就会知道在某个时候&#xff08;通常从大约4 GiB开始&#xff09;&#xff0c;您将开始遇到垃圾回收暂停的问题。 我不会详细介绍为什么在JVM中会出现暂停&#xff0c;但是总之&#xff0c;当JVM进行完整的收集并且您有很大的堆时&am…

MySQL学习笔记1(增删查改)

创建表&#xff1a; /*创建数据库create database 数据库名; */ CREATE DATABASE mybase; /*使用数据库use 数据库名 */ USE mybase;/*创建数据表的格式create table 表名(列名1 数据类型 约束,列名2 数据类型 约束,列名3 数据类型 约束);创建用户表,用户编号,姓名,用户的地址将…

Angular4 中内置指令的基本用法

ngFor 作用&#xff1a;像 for 循环一样&#xff0c;可以重复的从数组中取值并显示出来。 // .tsthis.userInfo [张三, 李四, 王五];// .html<div class"ui list" *ngFor"let username of userInfo"><div class"item">{{username}}…

初入编程的新世界

准备跨入程序员的行列了&#xff0c; 今天开课第一天&#xff0c; 算起来之前学习的几天&#xff0c; 第一次真正的了解了网页制作包括什么&#xff0c; html&#xff08;结构&#xff09;&#xff0c;css&#xff08;页面美化 层叠样式表&#xff09;&#xff0c;JavaScri…

java中i+=2什么意思_三分钟看懂Java中i++与++i的性能差别以及循环中如何使用

在Java中&#xff0c;自增是一种非常常见的操作&#xff0c;在自增中&#xff0c;有两种写法&#xff0c;一种是前缀自增(i)&#xff0c;一种是后缀自增(i)。这里主要简单介绍两种自增的差别。一、含义差别前缀自增和后缀自增是不同的。前缀自增(i)是从内存中加载i&#xff0c;…

Java / JEE中的有效日志记录–映射的诊断上下文

当我和一位同事坐在一起解决一些应用程序问题时&#xff0c;一切都开始了&#xff0c;当时我注意到了一些有趣的事情。 他正在合并代码&#xff0c;我的眼睛吸引了此类“ org.apache.log4j.MDC”的注意。 这导致了以下发现&#xff1a; 什么是MDC&#xff1f; MDC代表“ 映射诊…

bzoj1049[HAOI2006]数字序列

1049: [HAOI2006]数字序列 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1813 Solved: 789[Submit][Status][Discuss]Description 现在我们有一个长度为n的整数序列A。但是它太不好看了&#xff0c;于是我们希望把它变成一个单调严格上升的序列。但是不希望改变过多的数&…

具有Aspects的Java中的Mixin –用于Scala特性示例

Scala特征允许将新行为混合到一个类中。 考虑两个特征&#xff0c;可以向JPA实体添加审核和与版本相关的字段&#xff1a; package mvcsample.domainimport javax.persistence.Version import scala.reflect.BeanProperty import java.util.Datetrait Versionable {VersionBea…

前端:HTML

1,web服务的本质 import socketsk socket.socket()sk.bind(("127.0.0.1", 8080)) sk.listen(5)while True:conn, addr sk.accept()data conn.recv(8096)conn.send(b"HTTP/1.1 200 OK\r\n\r\n")conn.secd(b"<h1>Hello world!</h1>"…

动态规划:从新手到专家

作者&#xff1a;Hawstein出处&#xff1a;http://hawstein.com/posts/dp-novice-to-advanced.html前言 本文翻译自TopCoder上的一篇文章&#xff1a; Dynamic Programming: From novice to advanced &#xff0c;并非严格逐字逐句翻译&#xff0c;其中加入了自己的一些理解。水…