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

简介: 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

 

相关文章
|
1月前
|
Linux
一个进程最多可以创建多少个线程基本分析
一个进程最多可以创建多少个线程基本分析
40 1
|
3月前
|
监控 Linux 编译器
多线程死锁检测的分析与实现(linux c)-有向图的应用
在日常的软件开发中,多线程是不可避免的,使用多线程中的一大问题就是线程对锁的不合理使用造成的死锁,死锁一旦发生,将导致多线程程序响应时间长,吞吐量下降甚至宕机崩溃,那么如何检测出一个多线程程序中是否存在死锁呢?在提出解决方案之前,先对死锁产生的原因以及产生的现象做一个分析。最后在用有向环来检测多线程中是否存在死锁的问题。
56 0
|
6月前
|
存储 Java
java之线程死锁和ThreadLocal的使用
java之线程死锁和ThreadLocal的使用
|
3月前
|
数据处理
多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)
多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)
43 1
|
1月前
|
存储 安全 Java
并发编程知识点(volatile、JMM、锁、CAS、阻塞队列、线程池、死锁)
并发编程知识点(volatile、JMM、锁、CAS、阻塞队列、线程池、死锁)
71 3
|
29天前
|
存储 算法 Linux
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
25 0
|
2月前
|
数据处理 UED 开发者
Python并发编程之协程与多线程对比分析
本文将从Python并发编程的角度出发,对比分析协程与多线程两种并发处理方式的优缺点及适用场景,帮助读者更好地选择适合自己项目的并发方案。
|
2月前
|
程序员 测试技术 数据处理
Python中的装饰器应用与实现Python并发编程之协程与多线程对比分析
在Python编程中,装饰器是一种强大的工具,能够简洁而优雅地扩展函数或类的功能。本文将深入探讨Python中装饰器的原理、应用场景以及实现方法,帮助读者更好地理解和运用这一重要的编程概念。 本文将从Python并发编程的角度出发,对比分析协程与多线程两种并发处理方式的优缺点及适用场景,帮助读者更好地选择适合自己项目的并发方案。
|
2月前
|
存储 监控 程序员
线程死锁检测组件逻辑与源码
线程死锁检测组件逻辑与源码
67 2
|
6月前
|
Java 开发者
解锁Java多线程编程中的死锁之谜
解锁Java多线程编程中的死锁之谜
34 0

热门文章

最新文章

相关实验场景

更多