【转】Java并发基础实践--死锁

转载 2016年08月29日 22:52:25
本文是Java并发基础实践系列中的一篇,介绍了最简单的死锁场景,并使用jstack产生的thread dump来查找死锁。(2013.12.29最后更新)

1. 死锁
为了能够维护线程的安全性,Java提供的锁机制,但不恰当地使用锁则可能产生死锁。死锁是并发编程中一个无法绕开的问题。只要在一个任务中使用了一个以上的锁,那么就存在死锁的风险。
死锁产生的直接原因非常简单,即两个线程在相互等待对方所执有的锁。

2. 锁顺序死锁
在死锁场景中,最典型的就是锁顺序死锁,代码清单1就是一个很常见的示例。
清单1
public class DeadLock {

    
private Object leftLock = new Object();
    
private Object rightLock = new Object();

    
public void leftRight() {
        
synchronized (leftLock) {
            
try {
                TimeUnit.SECONDS.sleep(
3);
            } 
catch (InterruptedException e) {
                e.printStackTrace();
            }

            
synchronized (rightLock) {
                System.out.println(
"leftRight");
            }
        }
    }

    
public void rightLeft() {
        
synchronized (rightLock) {
            
try {
                TimeUnit.SECONDS.sleep(
3);
            } 
catch (InterruptedException e) {
                e.printStackTrace();
            }

            
synchronized (leftLock) {
                System.out.println(
"leftRight");
            }
        }
    }

    
public static void main(String[] args) {
        
final DeadLock deadLock = new DeadLock();

        Thread t1 
= new Thread(new Runnable() {

            @Override
            
public void run() {
                deadLock.leftRight();
            }
        });

        Thread t2 
= new Thread(new Runnable() {

            @Override
            
public void run() {
                deadLock.rightLeft();
            }
        });

        t1.start();
        t2.start();
    }
}

3. Thread Dump
JDK提供了一组命令行工具,其中就包括jstack。通过jstack可以获取当前正运行的Java进程的java stack和native stack信息。如果Java进程崩溃了,也可以通过它来获取core file中的java stack和native stack信息,以方便我们定位问题。
为了能够使用jstack去输出目标Java进程的thread dump,首先必须要弄清楚在执行清单1的程序时,该程序的进程号。JDK提供的另一个命令行工具jps可以获取系统中所有Java进程的相关信息。
在命令行窗口中执行命令jps,即可以得到清单2所示的结果
清单2
C:\Documents and Settings\Administrator>jps
2848
4552 DeadLock
5256 Jps
其中4552就是在笔者机器上执行程序DeadLock时所生成Java进程的进程号。
然后再执行命令jstack 4552,在笔者的机器上就会得到清单3所示的结果
清单3
C:\Documents and Settings\Administrator>jstack 
4552
2013-12-29 18:45:41
Full thread dump Java HotSpot(TM) Client VM (
23.25-b01 mixed mode, sharing):

"DestroyJavaVM" prio=6 tid=0x00878800 nid=0xd00 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" prio=6 tid=0x02b56c00 nid=0x14ec waiting for monitor entry [0x02fdf000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
33)
        - waiting to lock <0x22be6598> (a java.lang.Object)
        - locked <0x22be65a0> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
2.run(DeadLock.java:53)
        at java.lang.Thread.run(Thread.java:
724)

"Thread-0" prio=6 tid=0x02b55c00 nid=0x354 waiting for monitor entry [0x02f8f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
19)
        - waiting to lock <0x22be65a0> (a java.lang.Object)
        - locked <0x22be6598> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
1.run(DeadLock.java:45)
        at java.lang.Thread.run(Thread.java:
724)

"Service Thread" daemon prio=6 tid=0x02b34800 nid=0x133c runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread0" daemon prio=10 tid=0x02b13800 nid=0x10fc waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x02b11c00 nid=0x1424 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x02b10800 nid=0x1100 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x02af4c00 nid=0x1238 in Object.wait() [0x02daf000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x22b60fb8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:
135)
        - locked <0x22b60fb8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:
151)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:
189)

"Reference Handler" daemon prio=10 tid=0x02af0000 nid=0x12e8 in Object.wait() [0x02d5f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x22b60da0> (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 <0x22b60da0> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x02aee400 nid=0x129c runnable

"VM Periodic Task Thread" prio=10 tid=0x02b48000 nid=0x89c waiting on condition

JNI global references: 
117


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x02af4a3c (object 0x22be6598
, a java.lang.Object),
  which is held by 
"Thread-0"
"Thread-0":
  waiting to lock monitor 0x02af310c (object 0x22be65a0
, a java.lang.Object),
  which is held by 
"Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
33)
        - waiting to lock <0x22be6598> (a java.lang.Object)
        - locked <0x22be65a0> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
2.run(DeadLock.java:53)
        at java.lang.Thread.run(Thread.java:
724)
"Thread-0":
        at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
19)
        - waiting to lock <0x22be65a0> (a java.lang.Object)
        - locked <0x22be6598> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
1.run(DeadLock.java:45)
        at java.lang.Thread.run(Thread.java:
724)

Found 
1 deadlock.
在上述输出中,我们可以很明确地看到一个死锁
"Thread-1":
  waiting to lock monitor 0x02af4a3c (object 0x22be6598
, a java.lang.Object),
  which is held by 
"Thread-0"
"Thread-0":
  waiting to lock monitor 0x02af310c (object 0x22be65a0
, a java.lang.Object),
  which is held by 
"Thread-1"
并且它还标明了程序是在哪个地方时发现了上述死锁
"Thread-1":
        at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
33)
        - waiting to lock <0x22be6598> (a java.lang.Object)
        - locked <0x22be65a0> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
2.run(DeadLock.java:53)
        at java.lang.Thread.run(Thread.java:
724)
"Thread-0":
        at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
19)
        - waiting to lock <0x22be65a0> (a java.lang.Object)
        - locked <0x22be6598> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
1.run(DeadLock.java:45)
        at java.lang.Thread.run(Thread.java:
724)

4. 小结
死锁产生的直接原因非常简单,即两个线程在相互等待对方所执有的锁。锁顺序死锁是其中最经典的场景,此外还有动态的锁顺序死锁。虽然表现形式有所不同,但本质上都是两个线程在以不同的顺序来获取相同锁时,发生了死锁问题。

使用thread dump可以帮助我们分析死锁产生的原因。除了直接使用jstack命令来获取thread dump输出以外,JDK还提供了jvisualvm工具,它能以可视化的方式展示Java程序的进程号并导出thread dump。


原文:http://www.blogjava.net/jiangshachina/archive/2013/12/29/408180.html

java.lang.ref.Reference

Java代码  Reference提供了一些引用的基本方法以及静态代码块最高优先级启动ReferenceHandler线程  Reference提供了一些引用的基本方法以及静态代码块最高优先级启动Re...
  • huxin1
  • huxin1
  • 2011年04月03日 00:30
  • 2886

java并发编程实践学习(10)死锁

安全性和活跃度通常相互制约。我们使用锁来保证线程安全,但是滥用锁可能引起锁顺序死锁。一.死锁当一个线程永远占有一个锁,而其他线程尝试去获得这个锁,那么他们将永远阻塞。当线程A占有锁L时,想要获得锁M,...

GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,并发测试的方案等

iOS并发编程笔记,包含GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,...

Java基础11:线程;synchronized;延迟加载(懒汉模式);死锁

一、多线程 概述     1、进程:是一个正在执行中的程序。         (1)、每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。     2、线程:就是进程中的一个独立...

【Java基础】线程笔记——死锁

当线程需要同时持有多个锁时,有可能产生死锁 线程 A 当前持有互斥所锁 lock1,线程 B 当前持有互斥锁 lock2。接下来,当线程 A 仍然持有 lock1 时,它试图获取 lock2,因为线...

JAVA基础 day11 多线程 同步代码块 死锁问题

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。线程 是进程中的一个独立控制单元。线程控制着进程的执行。当一个程序启动时,就有一个进程被操作系...

Java基础——多线程+卖票程序+同步函数-单例设计模式+死锁

1.   线程 进程:是一个正在执行中的程序。         每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。   线程:就是进程中的一个独立的控制单元。         ...

java笔记:熟练掌握线程技术---基础篇之线程的协作和死锁的问题(下)

====================================================== 注:本文源代码点此下载 =============================...

java基础-5-多线程(2)-死锁与线程间通信(synchronized与Lock的区别及各自用法)

------- android培训、java培训、期待与您交流! ---------- 死锁         死锁是指多个应用程序进程间,因为对资源的竞争而造成的一种僵局(即互相等待...

java基础(死锁)

/* 死锁(同步中嵌套同步,而使用不同的锁) */ class Test implements Runnable { private boolean flag = true; Test...
  • amx50b
  • amx50b
  • 2015年12月16日 21:10
  • 182
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【转】Java并发基础实践--死锁
举报原因:
原因补充:

(最多只允许输入30个字)