多线程中的死锁举例与分析(转)

简介: 1. 一个特殊构造的程序考虑下面这个专门为说明多线程中的死锁现象而构造的程序: import java.util.LinkedList; public class Stack { public static void main(String[] args) { ...

 

1. 一个特殊构造的程序
考虑下面这个专门为说明多线程中的死锁现象而构造的程序:

import java.util.LinkedList;

public class Stack {
    public static void main(String[] args) {
        final Stack stack = new Stack();
        new Thread("push") {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    try {
                        Thread.sleep(10);//to make the deadlock occur
                    } catch (InterruptedException e) {
                    }
                    stack.push("object " + i);
                }
            }
        }.start();
        
        new Thread("pop") {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    try {
                        System.out.println(stack.pop());
                    } catch (Exception e) {
                    }
                }
            }
        }.start();
    }

    LinkedList<Object> list = new LinkedList<Object>();

    public synchronized void push(Object x) {
        System.out.println("begin to push " + x);
        synchronized (list) {
            list.addLast(x);
            notify();
        }
        System.out.println("end to push " + x);
    }

    public synchronized Object pop() throws Exception {
        System.out.println("begin to pop");
        synchronized (list) {
            if (list.size() <= 0) {
                wait();
            }
            return list.removeLast();
        }
    }
    
}

该程序构造了一个 Stack,启动了两个线程。一个线程向 Stack 中添加数据,另外一个线程从 Stack 中取出数据并打印。
但是运行程序后就会发现程序输出:

begin to pop
begin to push object 0

后,在再也没有后续输出了。

2. Dump 并分析线程状态
启动 jvisualvm 查看该程序线程的状态,将其 Dump,就可以得到以下线程堆栈信息:

"pop" prio=6 tid=0x00c00000 nid=0x2b0 in Object.wait() [0x00f9f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27f65648> (a loggerlock.Stack)
    at java.lang.Object.wait(Object.java:485)
    at loggerlock.Stack.pop(Stack.java:49)
    - locked <0x27f65658> (a java.util.LinkedList)
    - locked <0x27f65648> (a loggerlock.Stack)
    at loggerlock.Stack$2.run(Stack.java:26)

   Locked ownable synchronizers:
    - None

"push" prio=6 tid=0x00bfec00 nid=0x14c8 waiting for monitor entry [0x00f4f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at loggerlock.Stack.push(Stack.java:39)
    - waiting to lock <0x27f65658> (a java.util.LinkedList)
    - locked <0x27f65648> (a loggerlock.Stack)
    at loggerlock.Stack$1.run(Stack.java:16)

   Locked ownable synchronizers:
    - None

可以看到,pop 线程正在运行 wait(); 语句,处于 WAITING 状态,同时,该线程锁住了 list 和 stack 对象。
push 线程处于 BLOCKED 状态,等待其他线程释放 list 对象。


3. 运行过程及死锁原因分析

步骤

主程序

pop 线程

push 线程

1

启动

   

2

创建 stack 对象

   

3

创建 list 对象

   

4

 

启动

 

5

   

启动

6

   

sleep 10ms

7

 

调用 stack.pop()

 

8

 

锁住 stack 对象

 

9

 

打印 "begin to pop"

 

10

 

锁住 list 对象

 

11

 

调用 stack.wait()
(暂时释放 stack 对象)

 

12

   

锁住 stack 对象

13

   

打印 "begin to push 0"

14

   

企图锁住 list 对象
(发现 list 已被其他线程锁住)

15

进入死锁状态

 

http://www.educity.cn/it/sun/201004191051041573.htm

 

相关文章
|
3月前
|
存储 NoSQL Redis
Redis 新版本引入多线程的利弊分析
【10月更文挑战第16天】Redis 新版本引入多线程是一个具有挑战性和机遇的改变。虽然多线程带来了一些潜在的问题和挑战,但也为 Redis 提供了进一步提升性能和扩展能力的可能性。在实际应用中,我们需要根据具体的需求和场景,综合评估多线程的利弊,谨慎地选择和使用 Redis 的新版本。同时,Redis 开发者也需要不断努力,优化和完善多线程机制,以提供更加稳定、高效和可靠的 Redis 服务。
71 1
|
3月前
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
87 0
|
1月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
56 4
|
3月前
|
安全 Java 程序员
【多线程-从零开始-肆】线程安全、加锁和死锁
【多线程-从零开始-肆】线程安全、加锁和死锁
57 0
|
4月前
|
并行计算 API 调度
探索Python中的并发编程:线程与进程的对比分析
【9月更文挑战第21天】本文深入探讨了Python中并发编程的核心概念,通过直观的代码示例和清晰的逻辑推理,引导读者理解线程与进程在解决并发问题时的不同应用场景。我们将从基础理论出发,逐步过渡到实际案例分析,旨在揭示Python并发模型的内在机制,并比较它们在执行效率、资源占用和适用场景方面的差异。文章不仅适合初学者构建并发编程的基础认识,同时也为有经验的开发者提供深度思考的视角。
|
5月前
|
存储 监控 Java
|
5月前
|
安全 Java 开发者
Swing 的线程安全分析
【8月更文挑战第22天】
73 4
|
5月前
|
Java 数据库连接 数据库
当线程中发生异常时的情况分析
【8月更文挑战第22天】
134 4
|
5月前
|
安全 Java 程序员
线程安全与 Vector 类的分析
【8月更文挑战第22天】
90 4
|
5月前
|
存储 缓存 安全
深度剖析Java HashMap:源码分析、线程安全与最佳实践
深度剖析Java HashMap:源码分析、线程安全与最佳实践