1、多線程死鎖
a. 死鎖分析:
假設A和B同時在吃意大利面,而吃意大利面的條件是左手使用湯勺,右手使用叉子。現在只有一副餐具,A拿到了湯勺,B拿到了叉子,A等待B放下叉子,B等待A放下湯勺。則形成了死鎖。
b. 出現死鎖的條件:
- 具有多個SharedResource參與者,相當于湯勺和叉子。
- 線程鎖定了一個SharedResource之后,在未解鎖的情況下去鎖定另一個SharedResource參與者,相當于A在擁有了湯勺之后,又去拿叉子;B在擁有了叉子之后又去拿湯勺。
- 獲取SharedResource參與者的順序不固定,參與者順序對等,相當于湯勺和叉子的順序相同,沒有先后關系。
c. 上述1、2、3三個條件只要破壞了其中一種,則就解決了死鎖的問題。
2、提高多線程執行性能的兩種方式:
減少 SharedResource參與者參與者的個數,從而減少synchronized使用數量,減少獲取對象鎖的操作時間
盡量縮短臨界區范圍,從而減少線程沖突時等待的時間。
3、自己設計線程鎖
oid method() {
lock(); //鎖
try {
..
} finally {
unlock(); //最后無論什么情況都要解鎖
}
}
lock(); //鎖
try {

} finally {
unlock(); //最后無論什么情況都要解鎖
}
}
4、原子操作
- 用synchronized定義的方法或者塊都具有原子性,只能被一個線程使用
- long、double為非原子性,其他類型以及對象等引用都是具有原子性
- 在定義long、double類型變量時,使用volatile修飾,表示對這個字段變量的定義為不可分隔的
總結:
- 基本類型、引用類型為原子操作
- long、double為可以分割的
- 在多線程中使用其作為共享參與者使用時,要么在使用時的方法用synchronized定義,或者使用volatile聲明
5、意大利面死鎖問題解決方案
設計思路是將湯勺和叉子作為一個整體去處理,這樣就解決了死鎖的問題。
還有一種方法就是在添加湯勺和叉子時是有序的,必須先拿湯勺,再拿叉子,這樣也可以解決死鎖問題。
//主方法,用于創建處理
public class Main {
public static void main(String[] args) {
Tool spoon = new Tool("spoon");
Tool fork = new Tool("fork");
Tools tools = new Tools(spoon, fork);
new EaterThread(tools, "shma").start();
new EaterThread(tools, "jjq").start();
}
}
public class Main {
public static void main(String[] args) {
Tool spoon = new Tool("spoon");
Tool fork = new Tool("fork");
Tools tools = new Tools(spoon, fork);
new EaterThread(tools, "shma").start();
new EaterThread(tools, "jjq").start();
}
}
1 // 吃意大利面的線程 不斷的吃
2 class EaterThread extends Thread {
3 private String name;
4 private final Tool leftHand;
5 private final Tool rightHand;
6 public EaterThread(Tools tools, String name) {
7 super();
8 this.leftHand = tools.getSpoon();
9 this.name = name;
10 this.rightHand = tools.getFork();
11 }
12 public void eat() {
13 synchronized(leftHand) {
14 System.out.println(name + " takes up " + leftHand + "(left)");
15 synchronized(rightHand) {
16 System.out.println(name + " takes up " + rightHand + "(right)");
17 System.out.println(name + " is eating now!");
18 System.out.println(name + " puts down " + rightHand + "(right)");
19 }
20 System.out.println(name + " puts down " + leftHand + "(left)");
21 }
22 }
23
24 @Override
25 public void run() {
26 while(true) {
27 eat();
28 try {
29 Thread.sleep(1000);
30 } catch (InterruptedException e) {
31 // TODO Auto-generated catch block
32 e.printStackTrace();
33 }
34 }
35 }
36
37 }
2 class EaterThread extends Thread {
3 private String name;
4 private final Tool leftHand;
5 private final Tool rightHand;
6 public EaterThread(Tools tools, String name) {
7 super();
8 this.leftHand = tools.getSpoon();
9 this.name = name;
10 this.rightHand = tools.getFork();
11 }
12 public void eat() {
13 synchronized(leftHand) {
14 System.out.println(name + " takes up " + leftHand + "(left)");
15 synchronized(rightHand) {
16 System.out.println(name + " takes up " + rightHand + "(right)");
17 System.out.println(name + " is eating now!");
18 System.out.println(name + " puts down " + rightHand + "(right)");
19 }
20 System.out.println(name + " puts down " + leftHand + "(left)");
21 }
22 }
23
24 @Override
25 public void run() {
26 while(true) {
27 eat();
28 try {
29 Thread.sleep(1000);
30 } catch (InterruptedException e) {
31 // TODO Auto-generated catch block
32 e.printStackTrace();
33 }
34 }
35 }
36
37 }