死锁分析(嵌入式系统导论实验报告
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.实验结果
死锁产生的四个条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
产生死锁的解释
- 这里的A和B的两个方法都是使用了synchronized这个关键字,因此这两个类的对象就满足互斥条件
- 在代码中,当进程被阻塞时并不会自动释放自身拥有的资源,因此满足请求与保持条件
- 根据Java的机制,不会强行剥夺已经拥有的资源,因此满足不剥夺条件
- 有一种情况会产生“循环等待条件”,当b进入自己的methodB函数,但是还未调用a的last函数时被系统切换到主线程执行a的methodA函数,这时候子线程拥有了b的对象锁,主线程拥有了a的对象锁。那么无论接下去是哪个线程执行,都会在调用last函数的时候被阻塞,于是主线程在等待b的锁,子线程在等待a的锁,于是循环等待,构成死锁
- 验证想法
我在原来的代码中加了两句输出:
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)同步代码块的访问将被阻塞。 这个误解也导致我一直没想通为什么死锁