浅谈如何避免死锁

一般来说,能够原子性地获取需要的多个锁,或者注意 调整对多个锁的获取顺序 ,就会比较好地避免死锁。

下面举一个例子:假设有2个锁A和B,两个线程T1和T2

1
2
3
4
5
T1代码
......
A.lock();
B.lock();
......
1
2
3
4
5
T2代码
......
B.lock();
A.lock();
......

可能出现的死锁情况:
T1获取到A锁,等待B锁。
T2获取到B锁,等待A锁。
这个时候T1等不到B,而T2 也等不到A。

下面这种做法可以避免这样的死锁:

1
2
3
4
5
T1代码
......
A.lock();
B.lock();
......

1
2
3
4
5
T2代码
......
A.lock();
B.lock();
......

现在T1T2都是先获取A,再获取B,这样就可以避免死锁。因为两个线程都是先获取A才会接着获取B,就不会出现之前一个线程持有A等待B,另外一个线程持有B等待A的情况了。

此外,还有另外一种实现方式来避免死锁:

1
2
3
4
T1代码
......
GetLocks(A, B);
......

1
2
3
4
T2代码
......
GetLocks(A, B);
......

GetLocks函数是一次性的获取两个锁。这样就不会出现死锁的情况了。

此外,线程之间还会传递数据。因为这些线程公用进程的内存空间,所以线程间的传递数据就相对容易一些了。

本文内容来自大型网站系统与Java中间件实践