1. 同步弊端:
(1)效率低
(2)如果出現了同步嵌套,就容易產生死鎖問題
死鎖問題及其代碼 :
(1)是指兩個或者兩個以上的線程在執行的過程中,因爭奪資源產生的一種互相等待現象
(2)同步代碼塊的嵌套案例
1 package cn.itcast_02; 2 3 public class MyLock { 4 // 創建兩把鎖對象 5 public static final Object objA = new Object(); 6 public static final Object objB = new Object(); 7 }
1 package cn.itcast_02; 2 3 public class DieLock extends Thread { 4 5 private boolean flag; 6 7 public DieLock(boolean flag) { 8 this.flag = flag; 9 } 10 11 @Override 12 public void run() { 13 if (flag) { 14 synchronized (MyLock.objA) { 15 System.out.println("if objA"); 16 synchronized (MyLock.objB) { 17 System.out.println("if objB"); 18 } 19 } 20 } else { 21 synchronized (MyLock.objB) { 22 System.out.println("else objB"); 23 synchronized (MyLock.objA) { 24 System.out.println("else objA"); 25 } 26 } 27 } 28 } 29 }
1 package cn.itcast_02; 2 3 /* 4 * 同步的弊端: 5 * A:效率低 6 * B:容易產生死鎖 7 * 8 * 死鎖: 9 * 兩個或兩個以上的線程在爭奪資源的過程中,發生的一種相互等待的現象。 10 * 11 * 舉例: 12 * 中國人,美國人吃飯案例。 13 * 正常情況: 14 * 中國人:筷子兩支 15 * 美國人:刀和叉 16 * 現在: 17 * 中國人:筷子1支,刀一把 18 * 美國人:筷子1支,叉一把 19 */ 20 public class DieLockDemo { 21 public static void main(String[] args) { 22 DieLock dl1 = new DieLock(true); 23 DieLock dl2 = new DieLock(false); 24 25 dl1.start(); 26 dl2.start(); 27 } 28 }
我們執行的時候會發現程序會鎖住(當然這個只是很大幾率會鎖住):如下圖
這里死鎖我們該怎么解決呢?這里引出了線程之間通信:
?
不同種類的線程針對同一個資源的操作
?
?
?
?
2. 下面設置線程(生產者)和獲取線程(消費者)針對同一個學生對象進行操作示例:
代碼實現:
1 package cn.itcast_03; 2 3 /* 4 * 分析: 5 * 資源類:Student 6 * 設置學生數據:SetThread(生產者) 7 * 獲取學生數據:GetThread(消費者) 8 * 測試類:StudentDemo 9 * 10 * 問題1:按照思路寫代碼,發現數據每次都是:null---0 11 * 原因:我們在每個線程中都創建了新的資源,而我們要求的時候設置和獲取線程的資源應該是同一個 12 * 如何實現呢?這里是共享資源一種思路 13 * 在外界把這個數據創建出來,通過構造方法傳遞給其他的類。 14 * 15 */ 16 public class StudentDemo { 17 public static void main(String[] args) { 18 //創建資源----外界創建出資源 19 Student s = new Student(); 20 21 //設置和獲取的類(這兩個線程類被剛剛創建的資源綁定) 22 SetThread st = new SetThread(s);//通過構造方法傳遞給其他類 23 GetThread gt = new GetThread(s);//通過構造方法傳遞給其他類 24 25 //線程類 26 Thread t1 = new Thread(st); 27 Thread t2 = new Thread(gt); 28 29 //啟動線程 30 t1.start(); 31 t2.start(); 32 } 33 }
?
1 package cn.itcast_03; 2 3 public class SetThread implements Runnable { 4 5 private Student s; 6 7 public SetThread(Student s) { 8 this.s = s; 9 } 10 11 @Override 12 public void run() { 13 // Student s = new Student(); 14 s.name = "林青霞"; 15 s.age = 27; 16 } 17 18 }
?
1 package cn.itcast_03; 2 3 public class GetThread implements Runnable { 4 private Student s; 5 6 public GetThread(Student s) { 7 this.s = s; 8 } 9 10 @Override 11 public void run() { 12 // Student s = new Student();//上面SetThread()類中run()方法也出現Student s = new Student(),這樣就出現兩個不同的對象 13 System.out.println(s.name + "---" + s.age); 14 } 15 16 }
?
1 package cn.itcast_03; 2 3 public class Student { 4 String name; 5 int age; 6 }
上面代碼是有問題的,如下:
?
進一步改進上面代碼:
1 package cn.itcast_04; 2 3 /* 4 * 分析: 5 * 資源類:Student 6 * 設置學生數據:SetThread(生產者) 7 * 獲取學生數據:GetThread(消費者) 8 * 測試類:StudentDemo 9 * 10 * 問題1:按照思路寫代碼,發現數據每次都是:null---0 11 * 原因:我們在每個線程中都創建了新的資源,而我們要求的時候設置和獲取線程的資源應該是同一個 12 * 如何實現呢? 13 * 在外界把這個數據創建出來,通過構造方法傳遞給其他的類。 14 * 15 * 問題2:為了數據的效果好一些,我加入了循環和判斷,給出不同的值,這個時候產生了新的問題 16 * A:同一個數據出現多次 17 * B:姓名和年齡不匹配 18 * 原因: 19 * A:同一個數據出現多次 20 * CPU的一點點時間片的執行權,就足夠你執行很多次。 21 * B:姓名和年齡不匹配 22 * 線程運行的隨機性 23 * 線程安全問題: 24 * A:是否是多線程環境 是 25 * B:是否有共享數據 是 26 * C:是否有多條語句操作共享數據 是 27 * 解決方案: 28 * 加鎖。 29 * 注意: 30 * A:不同種類的線程都要加鎖。 31 * B:不同種類的線程加的鎖必須是同一把。 32 */ 33 public class StudentDemo { 34 public static void main(String[] args) { 35 //創建資源 36 Student s = new Student(); 37 38 //設置和獲取的類 39 SetThread st = new SetThread(s); 40 GetThread gt = new GetThread(s); 41 42 //線程類 43 Thread t1 = new Thread(st); 44 Thread t2 = new Thread(gt); 45 46 //啟動線程 47 t1.start(); 48 t2.start(); 49 } 50 }
?
1 package cn.itcast_04; 2 3 public class SetThread implements Runnable { 4 5 private Student s; 6 private int x = 0; 7 8 public SetThread(Student s) { 9 this.s = s; 10 } 11 12 @Override 13 public void run() { 14 while (true) { 15 synchronized (s) { 16 if (x % 2 == 0) { 17 s.name = "林青霞";//剛走到這里,就被別人搶到了執行權 18 s.age = 27; 19 } else { 20 s.name = "劉意"; //剛走到這里,就被別人搶到了執行權 21 s.age = 30; 22 } 23 x++; 24 } 25 } 26 } 27 }
?
1 package cn.itcast_04; 2 3 public class GetThread implements Runnable { 4 private Student s; 5 6 public GetThread(Student s) { 7 this.s = s; 8 } 9 10 @Override 11 public void run() { 12 while (true) { 13 synchronized (s) { 14 System.out.println(s.name + "---" + s.age); 15 } 16 } 17 } 18 }
?
1 package cn.itcast_04; 2 3 public class Student { 4 String name; 5 int age; 6 }
?
?