package day11;
class _15DeadLock {
publicstaticvoid main(String[] args){
MyTicket t=new MyTicket();
//两个线程共用一个t
Thread t1=new Thread(t);
Thread t2=new Thread(t);
//线程t1启动
t1.start();
try{
Thread.sleep(10);
}
catch(Exception e){
}
t.flag=false;
System.out.println("线程t2即将启动");
//线程t2启动
t2.start();
}
}
class MyTicketimplements Runnable{
privateinttick=1000;
Object obj=new Object();
booleanflag=true;
publicvoid run(){
if(flag){
while(true){
//同步代码块
synchronized(obj)//class锁
{ //*run方法循环中的*/
System.out.println(Thread.currentThread().getName()+"已获取run方法循环中的obj锁,尝试获取show方法锁");
show();
System.out.println(Thread.currentThread().getName()+"释放show方法锁");
}
}
}
else{
while(true){
//System.out.println("flag="+flag);
System.out.println(Thread.currentThread().getName()+"尝试获取show方法锁");
show();
System.out.println(Thread.currentThread().getName()+"释放show方法锁");
}
}
}
publicsynchronizedvoid show(){//this锁
System.out.println(Thread.currentThread().getName()+"已获取show方法锁,进入到show方法中,尝试获取obj锁");
synchronized(obj){
System.out.println(Thread.currentThread().getName()+"已获取show方法中obj锁,即将打印有效信息");
if(tick>0){
try{
Thread.sleep(10);
}
catch(Exception e){
}
System.out.println(Thread.currentThread().getName()+"....code"+tick--);
}
}
System.out.println(Thread.currentThread().getName()+"已释放show方法中的obj锁");
}
}
某次的运行结果如下:
Thread-0已获取run方法循环中的obj锁,尝试获取show方法锁
Thread-0已获取show方法锁,进入到show方法中,尝试获取obj锁
Thread-0已获取show方法中obj锁,即将打印有效信息
线程t2即将启动
Thread-0....code1000
Thread-0已释放show方法中的obj锁
Thread-0释放show方法锁
Thread-0已获取run方法循环中的obj锁,尝试获取show方法锁
Thread-1尝试获取show方法锁
Thread-0已获取show方法锁,进入到show方法中,尝试获取obj锁
Thread-0已获取show方法中obj锁,即将打印有效信息
Thread-0....code999
Thread-0已释放show方法中的obj锁
Thread-0释放show方法锁
Thread-1已获取show方法锁,进入到show方法中,尝试获取obj锁
Thread-0已获取run方法循环中的obj锁,尝试获取show方法锁
1. 从最后两行看出,一方面,Thread-1获得了show方法锁,然后尝试获取obj锁;但另一方面,Thread-0获得了obj锁,然后它尝试获取show方法锁。两个线程都在等待对方释放锁,此时造成了死锁现象。
2.此程序中,死锁产生的具体条件是一个同步代码块中含有另一个同步方法(Thread-0执行的代码部分),而此同步方法中含有另一个同步代码块(Thread-1执行的代码部分)。即你中有我,我中有你。。。。。。
3.锁其实就是一个条件,类似于if 语句,但是在线程中判断条件不易用条件语句进行表达,所以用synchronized关键字表示。
同一个obj锁可以用在多处,但相互独立,这里拥有跟别处无关,因为代码块执行完,锁自动解除了。
4.run方法中的if else就是将两个线程分开的条件。而且每个线程判断且仅判断一次。所以第一个线程判断结束后进入循环,而当主函数中flag=false执行后,随着t2.start(),第二个线程也开始运行起来,但它执行的是else里面的代码,直接要show方法锁。而此时再看看第一个线程,它是先要obj锁,然后再要show方法锁,在show方法锁获取后再次要obj锁。很显然,在线程一的运行过程中,只要能进入show方法,那么它必然可以运行show里面的方法,虽然show里还要再次获取obj锁,但是此时线程一已经获得了obj锁,所以它才能进入show方法再次要obj锁。
5.也就是说,线程一的运行中,每次要获取锁三次,其中有两次锁是同一个的。线程二的运行中,每次要获取锁两次,其中两次的锁是不同的。这里应该明白,两个线程能死锁,并不是两个线程都是要两次锁,而是一个三次,一个两次。
6.回过来,第二个线程的开启要凭借flag=false这一句,它让第二个线程走上了不同的运行道路,当然前提是t2.start()了。