Posted on 2012-04-28 08:20
马少 阅读(80)
评论(0) 编辑 收藏 所属分类:
Book-01 Java多线程设计模式
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();
//最后无论什么情况都要解锁
}
}
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();
}
}
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 }