关于java多线程死锁的实验

先上完整的代码

后续再依次修改代码块得到相应的结论

 1 //尝试写一个死锁 感受一下
 2 public class DeadLock {
 3 public static void main(String[] args) {
 4     Object o1 = new Object();
 5     Object o2 = new Object();
 6     //创建两个object对象
 7     //创建两个Thread线程
 8     Thread T1 = new Thread(new process1(o1,o2));   //两个线程T1、T2共享了相同的两个对象o1、o2
 9     Thread T2 = new Thread(new process2(o1,o2));
10     T1.setName("t1");
11     T2.setName("t2") ;
12     //star run一下
13     T1.start() ;  //----t2 running
14                   //-----t1 running
15     T2.start() ; 
16     
17     
18 }
19 }
20 //首先是写一个线程类。 
21 class process1 implements Runnable{
22     Object o1,o2;
23     process1(Object o1,Object o2 ){
24         this.o1 = o1 ;
25         this.o2 = o2 ; 
26         }
27     public void run(){
28         //先锁o1 再锁o2
29         synchronized(o1){
30             try{
31                 Thread.sleep(1000);  //锁住O1 并睡1s
32             }catch(Exception e ){
33                 e.printStackTrace();
34             }
35             synchronized(o2){ if(Thread.currentThread().getName().equals("t1")){ //T1成功执行后,输出t1并归还o1 o2两把锁
36         System.out.println("-----t1 running");}
37         if(Thread.currentThread().getName().equals("t2")){
38             System.out.println("----t2 running");}
39     }
40         }
41 }
42     }
43 
44 class process2 implements Runnable{
45     Object o1,o2;
46     process2(Object o1,Object o2 ){
47         this.o1 = o1 ;
48         this.o2 = o2 ; 
49         }
50     public void run(){
51         //先锁o2再锁o2 
52         synchronized (o2){  //锁住O2并睡1s
53             try{
54                 Thread.sleep(1000);  
55             }
56             catch(Exception e ){
57                 e.printStackTrace()  ;
58             }
59             synchronized(o1){ 
60                 if(Thread.currentThread().getName().equals("t1")){
61         System.out.println("-----t1 running");}
62         if(Thread.currentThread().getName().equals("t2")){ ////T2成功执行后,输出t2并归还o1 o2两把锁
63             System.out.println("----t2 running");}
64     }
65             }
66 }
67     }

实验的关键点在于运用Thread.sleep();对线程的休眠,实现对o1 o2不同的上锁和解锁情况。

代码块A(T1中的run方法):

public void run(){
28         //先锁o1 再锁o2
29         synchronized(o1){
30             try{
31                 Thread.sleep(1000);  //锁住O1 并睡1s
32             }catch(Exception e ){
33                 e.printStackTrace();
34             }
35             synchronized(o2){ if(Thread.currentThread().getName().equals("t1")){ //T1成功执行后,输出t1并归还o1 o2两把锁
36         System.out.println("-----t1 running");}
37         if(Thread.currentThread().getName().equals("t2")){
38             System.out.println("----t2 running");}
39     }
40         }
41 }

  

代码块B(T2中的run方法):

public void run(){
51         //先锁o2再锁o2 
52         synchronized (o2){  //锁住O2并睡1s
53             try{
54                 Thread.sleep(1000);  
55             }
56             catch(Exception e ){
57                 e.printStackTrace()  ;
58             }
59             synchronized(o1){ 
60                 if(Thread.currentThread().getName().equals("t1")){
61         System.out.println("-----t1 running");}
62         if(Thread.currentThread().getName().equals("t2")){ ////T2成功执行后,输出t2并归还o1 o2两把锁
63             System.out.println("----t2 running");}
64     }

实验1:将块A和B中的Thread.sleep(1000);语句都注释掉

输出结果:大定概率下

-----t1 running
----t2 running

小概率下输出

-----t2 running
----t1 running   出现这样的结果是因为T1更容易获得了较多的CPU时间块,将所有语句执行完毕,并解锁o1 o2,之后才执行T2.star()语句,输出t2 running

实验2:将块A中的Thread.sleep(1000);注释掉

输出结果:很大的几率会输出

-----t1 running

--------中间间隔1s后:
----t2 running

,原因在于语句先执行T1.star()

线程T1中的run语句执行完毕时,线程T2才开始获得CPU时间片,此时的o1 o2已经解锁。T2的run语句块可以顺利执行(包括sleep语句)

很小的几率会出现死锁:此时T2率先获得CPU时间片,并且锁住o2,线程停止1s,这段时间已经足够T1的run语句将o1锁住,于是o1 o2的锁都无法归还 ,形成了死锁

实验3:将块A和块B中的Thread.sleep(1000)都注释掉

输出结果:

必定没有输出,原因在于无论T1还是T2先拿到CPU时间片,都会拿掉一个锁,并且线程阻塞1s,这段时间已经足够另一个线程去拿另外一个锁,于是o1 o2的锁都无法归还,T1 T2中的run语句均无法继续往下执行,程序被锁死。

猜你喜欢

转载自www.cnblogs.com/Insertt/p/12117014.html