文章标题

来源:互联网 发布:数据部门团建出行标语 编辑:程序博客网 时间:2024/06/06 19:13

死锁分析(嵌入式系统导论实验报告


1.实验题目

死锁

分析下述代码,解释为什么会产生死锁

class Deadlock implements Runnable{    A a = new A();    B b = new B();    Deadlock(){        Thread t = new Thread(this);        int count = 30000;        t.start();        while(count-->0);        a.methodA(b);    }    public void run() {        b.methodB(a);    }    public static void main(String args[]) {        new Deadlock();    }}class A{    synchronized void methodA(B b){        b.last();    }    synchronized void last(){        System.out.println("Inside A.last()");    }}class B{    synchronized void methodB(A a){        a.last();    }    synchronized void last(){        System.out.println("inside B.last()");    }}

2.实验结果

死锁结果

  1. 死锁产生的四个条件

    1. 互斥条件:一个资源每次只能被一个进程使用。
    2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
    4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
  2. 产生死锁的解释

    1. 这里的A和B的两个方法都是使用了synchronized这个关键字,因此这两个类的对象就满足互斥条件
    2. 在代码中,当进程被阻塞时并不会自动释放自身拥有的资源,因此满足请求与保持条件
    3. 根据Java的机制,不会强行剥夺已经拥有的资源,因此满足不剥夺条件
    4. 有一种情况会产生“循环等待条件”,当b进入自己的methodB函数,但是还未调用a的last函数时被系统切换到主线程执行a的methodA函数,这时候子线程拥有了b的对象锁,主线程拥有了a的对象锁。那么无论接下去是哪个线程执行,都会在调用last函数的时候被阻塞,于是主线程在等待b的锁,子线程在等待a的锁,于是循环等待,构成死锁
    5. 验证想法
      我在原来的代码中加了两句输出:
      class A{synchronized void methodA(B b){    System.out.println("Inside A.methodA()");//add by myself    b.last();}synchronized void last(){    System.out.println("Inside A.last()");}class B{synchronized void methodB(A a){    System.out.println("inside B.methodB()");//add by myself    a.last();}synchronized void last(){    System.out.println("inside B.last()");}

    这时候就会第一次死锁(因为输出比较耗时),根据输出我们可以知道,确实是在两个线程分别进入methodA与methodB但是还没调用last的情况下产生死锁,下面是改完之后的结果:
    结果

3.实验心得

  • 对基础知识也要认真对待。 之前粗略看了一下Java的synchronized语法,却误以为只是对函数本身加锁而已,然而事实却是当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。 这个误解也导致我一直没想通为什么死锁
原创粉丝点击