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

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

 

相关文章
|
5月前
|
设计模式 消息中间件 安全
【JUC】(3)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
JUC专栏第三篇,带你继续深入JUC! 本篇文章涵盖内容:保护性暂停、生产者与消费者、Park&unPark、线程转换条件、多把锁情况分析、可重入锁、顺序控制 笔记共享!!文章全程干货!
396 1
|
6月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
|
存储 NoSQL Redis
Redis 新版本引入多线程的利弊分析
【10月更文挑战第16天】Redis 新版本引入多线程是一个具有挑战性和机遇的改变。虽然多线程带来了一些潜在的问题和挑战,但也为 Redis 提供了进一步提升性能和扩展能力的可能性。在实际应用中,我们需要根据具体的需求和场景,综合评估多线程的利弊,谨慎地选择和使用 Redis 的新版本。同时,Redis 开发者也需要不断努力,优化和完善多线程机制,以提供更加稳定、高效和可靠的 Redis 服务。
351 1
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
354 0
|
并行计算 安全 Java
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
1134 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
539 4
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
227 0
|
存储 监控 Java
|
安全 Java 开发者
Swing 的线程安全分析
【8月更文挑战第22天】
376 4
|
安全 Java 程序员
【多线程-从零开始-肆】线程安全、加锁和死锁
【多线程-从零开始-肆】线程安全、加锁和死锁
288 0

热门文章

最新文章