1. 程式人生 > 其它 >Java多執行緒(五)執行緒死鎖

Java多執行緒(五)執行緒死鎖

死鎖

1.死鎖的理解:不同的執行緒分別佔用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了執行緒的死鎖

2.說明:

1)出現死鎖後,不會出現異常,不會出現提示,只是所有的執行緒都處於阻塞狀態,無法繼續
2)我們使用同步時,要避免出現死鎖。

 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4 
 5         StringBuffer s1 = new StringBuffer();
 6         StringBuffer s2 = new StringBuffer();
7 8 9 new Thread(){ 10 @Override 11 public void run() { 12 13 synchronized (s1){ 14 15 s1.append("a"); 16 s2.append("1"); 17 18 try { 19 Thread.sleep(100); 20 } catch
(InterruptedException e) { 21 e.printStackTrace(); 22 } 23 24 synchronized (s2){ 25 s1.append("b"); 26 s2.append("2"); 27 28 System.out.println(s1); 29 System.out.println(s2);
30 } 31 } 32 } 33 }.start(); 34 35 36 new Thread(new Runnable() { 37 @Override 38 public void run() { 39 synchronized (s2){ 40 41 s1.append("c"); 42 s2.append("3"); 43 44 try { 45 Thread.sleep(100); 46 } catch (InterruptedException e) { 47 e.printStackTrace(); 48 } 49 50 synchronized (s1){ 51 s1.append("d"); 52 s2.append("4"); 53 54 System.out.println(s1); 55 System.out.println(s2); 56 } 57 } 58 } 59 }).start(); 60 } 61 }

死鎖的演示

 1 package com.atguigu.java1;
 2 //死鎖的演示
 3 class A {
 4     public synchronized void foo(B b) { //同步監視器:A類的物件:a
 5         System.out.println("當前執行緒名: " + Thread.currentThread().getName()
 6                 + " 進入了A例項的foo方法"); // 7 //        try {
 8 //            Thread.sleep(200);
 9 //        } catch (InterruptedException ex) {
10 //            ex.printStackTrace();
11 //        }
12         System.out.println("當前執行緒名: " + Thread.currentThread().getName()
13                 + " 企圖呼叫B例項的last方法"); //
14         b.last();
15     }
16 
17     public synchronized void last() {//同步監視器:A類的物件:a
18         System.out.println("進入了A類的last方法內部");
19     }
20 }
21 
22 class B {
23     public synchronized void bar(A a) {//同步監視器:b
24         System.out.println("當前執行緒名: " + Thread.currentThread().getName()
25                 + " 進入了B例項的bar方法"); //26 //        try {
27 //            Thread.sleep(200);
28 //        } catch (InterruptedException ex) {
29 //            ex.printStackTrace();
30 //        }
31         System.out.println("當前執行緒名: " + Thread.currentThread().getName()
32                 + " 企圖呼叫A例項的last方法"); //
33         a.last();
34     }
35 
36     public synchronized void last() {//同步監視器:b
37         System.out.println("進入了B類的last方法內部");
38     }
39 }
40 
41 public class DeadLock implements Runnable {
42     A a = new A();
43     B b = new B();
44 
45     public void init() {
46         Thread.currentThread().setName("主執行緒");
47         // 呼叫a物件的foo方法
48         a.foo(b);
49         System.out.println("進入了主執行緒之後");
50     }
51 
52     public void run() {
53         Thread.currentThread().setName("副執行緒");
54         // 呼叫b物件的bar方法
55         b.bar(a);
56         System.out.println("進入了副執行緒之後");
57     }
58 
59     public static void main(String[] args) {
60         DeadLock dl = new DeadLock();
61         new Thread(dl).start();
62 
63 
64         dl.init();
65     }
66 }

Lock(鎖)

  • 從JDK5.0開始,Java提供了更強大的執行緒同步機制——通過顯示定義同步鎖物件來實現同步。同步鎖使用Lock物件充當。
  • java.util.concurrent.locks.Lock介面是控制多個執行緒對共享資源進行訪問的工具。鎖提供了對共享資源的獨佔訪問,每次只能有一個執行緒對Lock物件加鎖,執行緒開始訪問共享資源之前應先獲得Lock物件。
  • ReentrantLock類實現了Lock,它擁有與synchronized相同的併發性和記憶體語義,在實現執行緒安全的控制中,比較常用的是ReentrantLock,可以顯式加鎖、釋放鎖。
 1 package com.atguigu.java1;
 2 
 3 import java.util.concurrent.locks.ReentrantLock;
 4 
 5 /**
 6  * 解決執行緒安全問題的方式三:Lock鎖  --- JDK5.0新增
 7  *
 8  * 1. 面試題:synchronized 與 Lock的異同?
 9  *   相同:二者都可以解決執行緒安全問題
10  *   不同:synchronized機制在執行完相應的同步程式碼以後,自動的釋放同步監視器
11  *        Lock需要手動的啟動同步(lock()),同時結束同步也需要手動的實現(unlock())
12  *
13  * 2.優先使用順序:
14  * Lock  同步程式碼塊(已經進入了方法體,分配了相應資源)  同步方法(在方法體之外)
15  *
16  *
17  *  面試題:如何解決執行緒安全問題?有幾種方式
18  */
19 class Window implements Runnable{
20 
21     private int ticket = 100;
22     //1.例項化ReentrantLock
23     private ReentrantLock lock = new ReentrantLock();
24 
25     @Override
26     public void run() {
27         while(true){
28             try{
29 
30                 //2.呼叫鎖定方法lock()
31                 lock.lock();
32 
33                 if(ticket > 0){
34 
35                     try {
36                         Thread.sleep(100);
37                     } catch (InterruptedException e) {
38                         e.printStackTrace();
39                     }
40 
41                     System.out.println(Thread.currentThread().getName() + ":售票,票號為:" + ticket);
42                     ticket--;
43                 }else{
44                     break;
45                 }
46             }finally {
47                 //3.呼叫解鎖方法:unlock()
48                 lock.unlock();
49             }
50 
51         }
52     }
53 }
54 
55 public class LockTest {
56     public static void main(String[] args) {
57         Window w = new Window();
58 
59         Thread t1 = new Thread(w);
60         Thread t2 = new Thread(w);
61         Thread t3 = new Thread(w);
62 
63         t1.setName("視窗1");
64         t2.setName("視窗2");
65         t3.setName("視窗3");
66 
67         t1.start();
68         t2.start();
69         t3.start();
70     }
71 }