`
uule
  • 浏览: 6350418 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

死锁案例

 
阅读更多

JAVA死锁与解决

死锁如何解决

 

互请不循

死锁产生的原因及四个必要条件

产生死锁的原因主要是:

(1) 因为系统资源不足

(2) 进程运行推进的顺序不合适

(3) 资源分配不当等。

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则

就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

 

产生死锁的四个必要条件:

(1) 互斥条件一个资源每次只能被一个进程使用

(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放

(3) 不剥夺条件 : 进程已获得的资源,在末使用完之前,不能强行剥夺

(4) 循环等待条件 : 若干进程之间形成一种头尾相接的循环等待资源关系

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之

一不满足,就不会发生死锁。

 

死锁的解除与预防:

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和

解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确

定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态

的情况下占用资源。因此,对资源的分配要给予合理的规划。

====================================================================

 假设有两个线程,分别代表两个饥饿的人,他们必须共享刀叉并轮流吃饭。他们都需要获得两个锁:共享刀和共享叉的锁。

  假如线程 “A”获得了刀,而线程“B”获得了叉。线程“A”就会进入阻塞状态来等待获得叉,而线程“B”则阻塞来等待“A”所拥有的刀。这样就造成了死锁。

 

 

避免死锁的一个通用的经验法则是:

当几个线程都要访问共享资源A、B、C时,保证使每个线程都按照同样的顺序去访问它们,比如都先访问A,在访问B和C。 

让所有的线程按照同样的顺序获得一组锁。

 

 

死锁就是两个或两个以上的线程被无限的阻塞,线程之间相互等待所需资源。这种情况可能发生在当两个线程尝试获取其它资源的锁,而每个线程又陷入无限等待其它资源锁的释放,除非一个用户进程被终止。就 JavaAPI 而言,线程死锁可能发生在一下情况。

  • 当两个线程相互调用 Thread.join ()
  • 当两个线程使用嵌套的同步块,一个线程占用了另外一个线程必需的锁,互相等待时被阻塞就有可能出现死锁。

 

 

下面这道题,是考死锁的,比较简单,想两个问题:

1.什么时候会造成死锁

2.wait和notify释放了哪个锁,因为题目中有两个锁。

 

import java.util.LinkedList;


public class DeadLockTest {
    LinkedList list = new LinkedList();  
      
    public synchronized void push(Object x) {  
        System.out.println("push");
        synchronized (list) {  
            list.addLast(x);  
            notify();  
        }  
    }  
  
    public synchronized Object pop() throws Exception {    
        synchronized (list) {  
            if (list.size() <= 0) {  
                wait();  
            }  
            return list.removeLast();  
        }  
    }  
    
    public static void main(String[] args) throws InterruptedException {
        final DeadLockTest deadLockTest = new DeadLockTest();
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    deadLockTest.pop();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        Thread.sleep(2000);
        Thread threadPush = new Thread(new Runnable() {
            public void run() {
                try {
                    deadLockTest.push("push thread");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        threadPush.start();
        
    }
}

 

 

当List为空时,pop的锁一直wait,需要唤醒,而push也获取不到List的锁,进而无法执行notify唤醒方法,所以死锁。

 

来源:http://tomyz0223.iteye.com/blog/1050230

 

Example2:

 

class DeadLockSample{  
    public final Object lock1 = new Object();  
    public final Object lock2 = new Object();    
    public void methodOne(){  
       synchronized(lock1){  
          ...  
          synchronized(lock2){...}  
       }  
    }  
  
    public void methodTwo(){  
       synchronized(lock2){  
      ...  
          synchronized(lock1){...}  
       }  
    }  
}  

 假设场景:线程A调用methodOne(),获得lock1的隐式锁后,在获得lock2的隐式锁之前线程B进入运行,调用methodTwo(),抢先获得了lock2的隐式锁,此时线程A等着线程B交出lock2,线程B等着lock1进入方法块,死锁就这样被创造出来了。 

 

 Example3:

 

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockOrdering {
    private Lock lock1 = new ReentrantLock();
    private Lock lock2 = new ReentrantLock();
  
    public void op1() {
        while(true) {
            if(lock1.tryLock()) {//先获取lock1
                try {
                    System.out.println("do sth in op1 with lock1...");
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (Exception e) {}
                    System.out.println("after sleep in op1");
                     
                    if(lock2.tryLock()) {//再获取lock2
                        try {
                            System.out.println("do sth in op1 with lock2...");
                            return;//退出循环
                        } finally {
                            lock2.unlock();
                        }
                    }
                } finally {
                    lock1.unlock();
                }
            }
        }
    }
  
    public void op2() {
        //锁获取的顺序与op1相反
        while(true) {
            if(lock2.tryLock()) {//先获取lock2
                try {
                    System.out.println("do sth in op2 with lock2...");
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (Exception e) {}
                    System.out.println("after sleep in op2");
                     
                    if(lock1.tryLock()) {//再获取lock1
                        try {
                            System.out.println("do sth in op2 with lock1...");
                            return;//退出循环
                        } finally {
                            lock1.unlock();
                        }
                    }
                } finally {
                    lock2.unlock();
                }
            }
        }
    }
  
    public static void main(String... args) {
        final LockOrdering test = new LockOrdering();
        new Thread() {
            public void run() {
                test.op1();
            }
        }.start();
        new Thread() {
            public void run() {
                test.op2();
            }
        }.start();
    }
}

 这只是个例子,简单的使用了tryLock,而实际上,带超时时间的重载版本的tryLock更实用。如果上述两个操作都同时做,op1获取lock1,op2获取lock2,op1将获取不到lock2,op2也获取不到lock1,然后op1释放lock1,op2释放lock2,接着又重复这样的操作,就可能导致死循环,当然,这只是理论上的一种可能性,实际CPU要做很多事情,并不会出现这类低概率事件。如果使用带超时时间的tryLock,且每次使用的时间都不同,则几乎可避免这类情况。这有点儿类似网络中的碰撞以及解决碰撞的二进制指数退避算法。

例子3来源:内置锁与LOCK

 

 

 

 

 

分享到:
评论

相关推荐

    这六个 MySQL 死锁案例,能让你理解死锁的原因!.doc

    MySQL 死锁案例详解 在 MySQL 中,死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象。死锁的产生原因是由于两个或两个以上的 Session 加锁的顺序不一致。解决死锁问题的关键就是让...

    数据库实战-收集一些常见的 MySQL 死锁案例.zip

    数据库实战-收集一些常见的 MySQL 死锁案例.zip 数据库实战-收集一些常见的 MySQL 死锁案例.zip 在工作过程中偶尔会遇到死锁问题,虽然这种问题遇到的概率不大,但每次遇到的时候要想彻底弄懂其原理并找到解决方案...

    收集一些常见的 MySQL 死锁案例

    这个项目收集了一些常见的 MySQL 死锁案例,大多数案例都来源于网络,并对其进行分类汇总,试图通过死锁日志分析出每种死锁的原因,还原出死锁现场。 实际上,我们在定位死锁问题时,不仅应该对死锁日志进行分析,...

    一些常见的MySQL死锁案例-mysql-deadlocks-master(源代码+案例+图解说明)

    这个项目收集了一些常见的 MySQL 死锁案例,大多数案例都来源于网络,并对其进行分类汇总,试图通过死锁日志分析出每种死锁的原因,还原出死锁现场。 实际上,我们在定位死锁问题时,不仅应该对死锁日志进行分析,还...

    数据库死锁案例

    ### 数据库死锁案例 #### 一、数据库死锁概述 数据库死锁是数据库系统中一个常见的问题,尤其是在并发环境中,多个事务同时访问共享资源时容易出现。死锁发生时,涉及的事务会陷入互相等待的状态,即每个事务都在...

    mysql死锁的一些案例

    这篇博客文章《mysql死锁的一些案例》可能深入探讨了MySQL中死锁的产生原因、表现形式以及解决策略。虽然具体内容未给出,但我们可以根据通常的死锁情况来进行分析。 1. **死锁产生的原因**: - 资源请求顺序不同...

    mysql-一些常见的mysql死锁案例-笔记记录.zip

    死锁的常见案例包括但不限于以下几种: 1. **资源顺序获取**:事务A持有资源1并请求资源2,而事务B持有资源2并请求资源1,双方形成循环等待,导致死锁。例如,两个事务分别对两条不同的记录进行更新操作,但顺序...

    操作系统\os 死锁.pdf

    #### 四、死锁案例分析 文档中提到了一个过桥的案例来形象地说明死锁现象。假设只允许单向通行的一座桥,每段桥视为一种资源,若两辆车分别从两端驶向桥中央,就会出现双方都无法前进的情况,即发生了死锁。解决这...

    Ibatis死锁

    描述中提到的博客链接(https://kanful.iteye.com/blog/969567)可能提供了一个具体的Ibatis死锁案例分析。通常,死锁的发生与并发事务的执行顺序、事务的隔离级别以及数据库的锁定机制有关。在Ibatis中,死锁可能...

    C例子:死锁too

    该程序是我写的博客“一起talk C栗子吧((第一百一十九回:C语言实例--线程死锁三)”的配套程序,共享给大家使用

    一个最不可思议的MySQL死锁分析1

    本文将深入探讨一个看似不可能发生的死锁案例,并分析其背后的原理。死锁通常发生在多个事务相互等待对方释放资源的情况下,但在这个特定的场景中,我们面对的是一个看似违背常理的情况。 首先,我们来看一下这个...

    死锁_Java产生死锁的简单案例

    本文通过一个简单的化妆类(Markup)和两个对象——口红(LipStick)和镜子(Mirror)的案例,展示了如何在Java中产生死锁。化妆类中的线程尝试同时持有这两个对象的锁,但顺序不同,从而导致了死锁。 首先,我们...

    大牛出手MySQL死锁深入分析

    本文将以一个具体的死锁案例为背景,深入分析MySQL中的死锁机制,探讨死锁的成因,并提出预防策略,旨在帮助读者清晰理解死锁问题的背景、阅读死锁日志的方法、深入剖析死锁的原因以及总结死锁问题。 首先,死锁...

    SQL Server死锁总结.rar

    文档中的"SQL_Server死锁总结.docx"可能会提供具体的死锁案例分析,包括死锁的触发条件、诊断过程和解决措施。"下载说明.txt"可能是关于如何获取和使用这些资源的说明,而"A5下载- 更全的站长资源平台.url"则可能是...

    PostgreSQL数据库典型故障案例及处理技巧.docx

    下面是一个典型的死锁案例: 错误内容: org.postgresql.util.PSQLException: 错误: 检测到死锁详细:进程 6533 等待在事务 36964707 上的 ShareLock; 由进程 10733 阻塞.进程 10733 等待在事务 36964708 上的 ...

Global site tag (gtag.js) - Google Analytics