如何解决多线程程序中的死锁问题
2016-03-21 21:22
537 查看
如何解决多线程程序中的死锁问题
(2011-05-03 15:10:13)转载▼
标签:
| 分类: java |
的确,死锁问题是一个比较令人头痛的问题:难重现,难调试,又相对隐蔽。但是因此把多线程一把拍死还是过于武断了:多线程在数据共享方面比多进程 方便多了;有些高性能场合必须多线程如epoll服务器;很多语言没有提供多进程的直接支持如Java。而且很多强大健壮的服务是用多线程写的(当然多进 程也很多),既然别人能做到,我们肯定也可以做到,怎么能直接举手投降呢?
死锁是由于不同线程按照不同顺序进行加锁而造成的。如:
线程A:对lock a加锁 => 对lock b加锁 => dosth => 释放lock b => 释放lock a
线程B:对lock b加锁 => 对lock a加锁 => dosth => 释放lock a => 释放lock b
这样两条线程,就可能发生死锁问题。要避免发生死锁,应该使用同一个顺序进行加锁。嗯。原理很简单,实现起来很困难。一方面人总有疏忽的时候,另 一方面回调函数、设计模式使得代码跳转的体位可以很复杂,也许在你没注意的情况下就犯了天条,然后就只能在下着雨的死锁夜,愤怒的咆哮啊有木有。所以呢应该由计算机来帮我们进行检验。我实现了一个可重入的带优先级的锁,每个锁均带有一个全局优先级,然后每个线程必须按照优先级从小到大的顺序进行加锁,解锁则反过来。比如有两个锁,优先级是1,2。 则:
lock 1 - lock 2 (OK)
lock 2 - lock 1 (ERROR:加锁顺序错)
lock 1 - lock 2 - lock1 - lock2 (OK)
lock 1 - lock 2 - unlock2 - unlock 1 (OK)
lock 1 - lock 2 - unlock1 (ERROR:解锁顺序错)
lock 1 - lock 2 - lock1 - unlock1 - unlock2 - unlock1 (OK)
lock 1 - lock 2 - lock1 - unlock1 - unlock1 (ERROR:解锁顺序错)
lock 1 - lock 2 - lock1 - unlock2 - unlock1 - unlock1 (OK)
注意:当已经持有某锁的时候,反复加锁总是成功。至于解锁,貌似有些奇怪,其实是为了效率考虑——如果保存所有加锁的细节,要求解锁顺序正好对偶当然逻辑更为严密,自己取舍吧。
这回代码是用Java写的,想看C++实现的移步:http://blog.sina.com.cn/s/blog_48d4cf2d0100mx4n.html
==============================代码的分割线=============================
import java.util.Stack;
public class PriorityLock {
private int pri = -1; // 锁对象的优先级,必须严格按照从小到大顺序请求锁,否则lock的时候抛异常
private long tid = -1; // 当前持有此锁的线程ID
private int lock_times = 0; // 持有该锁的次数
private static final ThreadLocal<Stack<Integer>> lstacks = new ThreadLocal<Stack<Integer>>();
public PriorityLock(int pri_) {
if (pri_ < 0) {
throw new RuntimeException("pri should be positive");
}
this.pri = pri_;
}
public synchronized void lock() throws InterruptedException {
long currentid = Thread.currentThread().getId();
if (tid == currentid) { // 允许重复加锁
++lock_times;
return;
}
Stack<Integer> stack = getLockStack();
if (!stack.empty() && stack.lastElement() >= pri) { // 当前持有的锁优先级大于等于新申请的锁,错误
throw new RuntimeException("lock in wrong order");
} else {
while (tid != -1) { // 锁-while-等-干-通,五字真言还记得吗
wait();
}
tid = currentid;
lock_times = 1;
stack.push(pri);
}
}
public synchronized void unlock() {
long currentid = Thread.currentThread().getId();
if (currentid != tid) {
throw new RuntimeException("unlock in bad manner"); // 斯巴达了,遇到不按规则玩的
}
if (lock_times > 1) {
--lock_times;
} else {
Stack<Integer> stack = getLockStack();
if (stack.empty() || stack.lastElement() != pri) {
throw new RuntimeException("unlock in bad manner"); // 再次斯巴达
}
stack.pop();
tid = -1;
lock_times = 0;
notifyAll();
}
}
private static Stack<Integer> getLockStack() {
Stack<Integer> stack = lstacks.get();
if (stack == null) {
stack = new Stack<Integer>();
lstacks.set(stack);
}
return stack;
}
}
相关文章推荐
- 下表操作符
- H5 - HTML5新增标签
- cygwin 安装 ffplay
- day11_分区表------子分区的母模板(10g)
- day11_分区表——分区表常用维护
- day11_分区表——11g新特性
- hdoj--1060--Leftmost Digit(数学)
- python的时间处理
- netty-mina深入学习与对比(一)
- eclipse结合axis2发布webservice踩坑记录
- CCD及CMOS尺寸计算
- spring学习笔记(10)@AspectJ研磨分析[1]入门、注解基本介绍
- 数据结构队列C++代码实现
- 使用ThreadGroup模拟线程池
- JAVA学习笔记(二)
- JAVA_String_字符串操作
- BZOJ solve 100 纪念
- iOS开发网络篇—数据安全
- Java爬虫,信息抓取的实现
- 网络框架之volley