1、死锁
锁是个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解。但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用。
如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程是死锁的。
让
我
们
先来看一段代
码
,
这
段代
码
会引起死
锁
,使
线
程
t1
和
线
程
t2
互相等待
对
方
释
放
锁。
public class DeadLockDemo {
privat static String A = "A";
private static String B = "B";
public static void main(String[] args) {
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override publicvoid run() {
synchronized (A) {
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println("1");
} } } });
Thread t2 = new Thread(new Runnable() {
@Override publicvoid run() {
synchronized (B) {
synchronized (A) {
System.out.println("2");
} } } });
t1.start();
t2.start();
}
}
这
段代
码
只是演示死
锁
的
场
景,在
现实
中你可能不会写出
这样
的代
码
。但是,在一些更
为复杂
的
场
景中,你可能会遇到
这样
的
问题
,比如
t1
拿到
锁
之后,因
为
一些异常情况没有
释
放
锁 (死循环
)。又或者是
t1
拿到一个数据
库锁
,
释
放
锁
的
时
候抛出了异常,没
释
放掉。
一旦出
现
死
锁
,
业务
是可感知的,因
为
不能
继续
提供服
务
了,那么只能通
过
dump
线
程
查
看 到底是哪个线
程出
现
了
问题
,以下
线
程信息告
诉
我
们
是
DeadLockDemo
类
的第
42
行和第
31
行引 起的死锁
。
"Thread-2" prio=5 tid=7fc0458d1000 nid=0x116c1c000 waiting for monitor entry [116c1b000] java.lang.Thread.State: BLOCKED (on object monitor) at com.ifeve.book.forkjoin.DeadLockDemo$2.run(DeadLockDemo.java:42) - waiting to lock <7fb2f3ec0> (a java.lang.String) - locked <7fb2f3ef8> (a java.lang.String) at java.lang.Thread.run(Thread.java:695)
"Thread-1" prio=5 tid=7fc0430f6800 nid=0x116b19000 waiting for monitor entry [116b18000] java.lang.Thread.State: BLOCKED (on object monitor) at com.ifeve.book.forkjoin.DeadLockDemo$1.run(DeadLockDemo.java:31) - waiting to lock <7fb2f3ef8> (a java.lang.String) - locked <7fb2f3ec0> (a java.lang.String) at java.lang.Thread.run(Thread.java:695)
产生死锁的原因:
1、竞争不可抢占性资源。
2、竞争可消耗资源。
当系统中供多个进程共享的资源如打印机,公用队列等,其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。
3、进程推进顺序不当。
进程在运行过程中,请求和释放资源的顺序不当,也同样会导致产生进程死锁。如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
1、 互斥条件:一个资源每次只能被一个进程使用。
2、 请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3 、不可抢占条件:进程已获得的资源,在末使用完之前,不能强行剥夺,只能在进程使用完时由自己释放。
4、 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
扫描二维码关注公众号,回复:
9163238 查看本文章
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。因此可以写下如下的预防死锁的方法。
避免死锁的几种方法
1、避免一个
线
程同
时获
取多个
锁
。
2、避免一个
线
程在
锁
内同
时
占用多个
资
源,尽量保
证
每个
锁
只占用一个
资
源。
3、尝试
使用定
时锁
,使用
lock.tryLock
(
timeout
)来替代使用内部
锁
机制。
4、对
于数据
库锁
,加
锁
和解
锁
必
须
在一个数据
库连
接里,否
则
会出
现
解
锁
失
败
的情况。