能否写一个容易产生死锁的程序?
死锁的现象:程序挂着不动了
死锁的本质:所有的钥匙都被占用了,导致双方都失去代码的执行权;
线程安全隐患:一个线程还没执行完必须同步的代码,cpu就把运行权交给另一个共享代码的线程了,导致错乱;
解决方案:把该同步完成的代码封装到一个{}中,再没有执行完之前,其他线程没有权利读取和执行该{}中的代码;
同步安全原理:给需要同步的代码加个锁(synchronized),给锁配一把钥匙(Object / this / .class ),谁在执行该代码,谁就得到对应的钥匙;
因为只有一把钥匙,所以其他线程没有钥匙,就打不开锁,就得不到锁中的代码,也就是没权利执行锁中的代码,这样就安全了;
有可能产生的问题:
当A线程执行到一半,失去cpu的执行权,B线程得到cpu执行权,B把锁中的代码执行到一半发现里边有一部分代码加了锁,可是钥匙在A线程代码的锁上,这时,B线程可住了,需要得到A线程执行完剩下的代码后才能拿到钥匙,杯具的事情来了,因为这时B线程锁上的钥匙刚好就是A线程剩下的代码的锁的钥匙,各持一把钥匙,而且钥匙都拿不出来,因为双方锁中的代码都没执行完;(这时就是死锁)
写一个死锁的代码:
思路:让两条线程,各持对方需要的钥匙;
1,A线程和B线程的run方法中的代码加上嵌套锁;
2,两条线程的嵌套锁共用两把钥匙;
3,B线程的外套锁共用A线程内套锁的钥匙,内套锁共用A线程的外套锁的钥匙;
代码体现:
public class DeadLockTest {
/**
* 面试:写一个死锁事例
* 两锁嵌套
*
* 同步安全的原理:
* 当A线程在执行一半的代码后失去执行权,那么共享这些代码的其他线程,没有权利执行这些代码;
* 只有当我把同步中的所有代码执行完,其他线程才能进来执行;
*
* 一锁不能二用,对象不可二用;
*
*/
public static class DeadLock implements Runnable {
//成员变量
private boolean flag;
//构造函数
DeadLock(boolean flag){
this.flag = flag;
}
//成员函数
public void run(){
//if else 制造双体
if(flag){
while(true){
synchronized(MyLock.keyb){
System.out.println("Thread 1 拿着 keyb");
synchronized(MyLock.keya){
System.out.println("Thread 1 拿着 keya");
System.out.println("Thread 1 释放 keya");
}
System.out.println("Thread 1 释放 keyb");
}
}
}
else{
while(true){
synchronized(MyLock.keya){
System.out.println("Thread 2 拿着 keya");
synchronized(MyLock.keyb){
System.out.println("Thread 2 拿着 keyb");
System.out.println("Thread 2 释放 keyb");
}
System.out.println("Thread 2 释放 keya");
}
}//复制死锁时,最后一部分打印结果:
/*
Thread 2 拿着 keya
Thread 2 拿着 keyb
Thread 2 释放 keyb
Thread 2 释放 keya
Thread 2 拿着 keya // 2拿a不放
Thread 1 拿着 keyb */ // 1拿b不放 两把钥匙被两个人拿到时,就死了
}
}
}
//准备两个锁的钥匙
public static class MyLock{
static Object keya = new Object();
static Object keyb = new Object();
}
public static void main(String[] args) {
// 建立事物对象
DeadLock d1 = new DeadLock(true);
DeadLock d2 = new DeadLock(false);
// 建立线程,把对象导入线程
Thread t1 = new Thread(d1);
Thread t2 = new Thread(d2);
// 启动线程
t1.start();
t2.start();
}
}