您的位置:首页 > 编程语言 > Java开发

Java多线程初探——死锁

2016-06-06 15:37 369 查看

一、死锁案例

Java多线程编程中,为了保证线程安全,用到了锁的概念,当两个线程互相等待对方释放同步的监视器时就会造成死锁。对于死锁,如果没有外力作用,死锁会一直继续下去,程序将无法正常往下执行。现在写一个简单的死锁案例。

先定义两个类,在这两个类中分别定义两个synchronized方法,这就表示如果有线程调用了对象中的方法,线程将持有该对象的锁。

ClassA.java

public class ClassA {

public synchronized void init(ClassB b) {
System.out.println("A对象的init方法执行了!");

try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A对象准备调用B对象的end方法!");
b.end();
}

public synchronized void end() {
System.out.println("A对象的end方法执行了!");
}

}ClassB.java
public class ClassB {

public synchronized void init(ClassA a) {
System.out.println("B对象的init方法执行了!");

try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("B对象准备调用A对象的end方法!");
a.end();
}

public synchronized void end() {
System.out.println("B对象的end方法执行了!");
}
}然后再写一个测试类
TestMain.java

public class TestMain implements Runnable{

public ClassA a = new ClassA();

public ClassB b = new ClassB();

public static void main(String[] args) {
TestMain main = new TestMain();
Thread thread = new Thread(main);

thread.start();
main.runB();
}

@Override
public void run() {
a.init(b);
}

public void runB() {
b.init(a);
}

}运行程序,执行结果如下:
B对象的init方法执行了!

A对象的init方法执行了!

B对象准备调用A对象的end方法!

A对象准备调用B对象的end方法!

程序在输出“A对象准备调用B对象的end方法!”之后就不再往下运行,但是从运行结果来看程序肯定是没有运行结束的,所以程序进入了一个假死的状态。

现在分析一下上面的代码

1、首先在main函数中定义一个子线程,然后调用线程的start()方法启动子线程,并且在main函数所在的线程(暂定叫做主线程)调用runB()方法,这样就有了两个线程在运行了。

2、在主线程的runB()方法中调用了ClassB对象的init方法,因为init方法有synchronized关键字,所以主线程获得ClassB对象的锁。程序首先输出B的init方法执行的内容,然后ClassB调用sleep方法执行休眠,休眠时不释放ClassB的对象锁,主线程让出CPU执行权,这时子线程获得CPU的执行权,子线程开始执行。

3、子线程调用ClassA的init方法,同样的获得了ClassA对象的锁并输出开始执行的内容,接着执行sleep方法开始休眠,子线程释放CPU执行权,但是不释放ClassA的对象锁。

4、这时主线程从休眠中醒来,获得CPU的执行权,准备执行ClassA的end方法,end方法也是被synchronized修饰的,所以主线程想获得ClassA的对象锁,但是因为ClassA的对象锁已被子线程拥有,所以主线程等待子线程释放锁。

5、接着子线程从休眠中醒来,准备执行ClassB的end方法,但是因为主线程拥有ClassB的对象锁,所以子线程也等待主线程释放锁,这就造成了相互等待的状态,程序不能继续往下执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息