1.什么是死锁?
线程A持有资源a等待b资源,线程B持有资源b等待a资源,形成死锁状态。
2.案例
public class Moive {
Object o1 = new Object();//资源o1
Object o2 = new Object();//资源o2
boolean flag;
public void buyAndWatch(String s) {
if (flag) {
synchronized (o1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s + "买票");
synchronized (o2) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s + "看电影");
}
}
}else {
synchronized (o2) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s + "买票");
synchronized (o1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s + "看电影");
}
}
}
}
public class MyRunnable implements Runnable {
Moive moive = new Moive();
@Override
public void run() {
moive.flag = true;
moive.buyAndWatch(Thread.currentThread().getName());
moive.flag = false;
moive.buyAndWatch(Thread.currentThread().getName());
}
}
测试:
public class LockTest {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable,"线程A:");
Thread t2 = new Thread(runnable,"线程B:");
t1.start();
t2.start();
}
}
结果形成死锁:
3.死锁的四个必要条件及解决方法
资源互斥:资源不能被共享,只能由一个线程使用(两个人的不能穿同一件衣服)
请求保持:拥有资源的线程在请求新的资源又不释放占有的资源(拿着别人需要的资源又去请求新的资源)
不可抢占:已经获得的资源在使用完成前不被别人剥夺(自己的资源不放手)
循环等待:各个线程对资源的需求构成一个循环(A线程需要B线程占用的资源,B线程需要C线程占用的资源,C线程需要A线程占用的资源)
解决办法:
1.调整申请锁的范围(不在锁上加锁)
2.调整申请锁的顺序()
3.人工检查:
在一个同步方法中,或在一个锁的保护的范围中,调用了其它对象的方法时,要注意:
a. 如果其它对象的方法会消耗比较长的时间,那么就会导致锁被我们持有了很长的时间;
b. 如果其它对象的方法是一个同步方法,那么就要注意避免发生死锁的可能性了;
总之尽量避免在一个同步方法中调用其它对象的延时方法和同步方法。
四个条件在死锁时会同时发生,破坏其中一个条件就可以打破死锁状态