在实际编程中,死锁虽然不常见,但是如果遇到死锁便是致命的。接下来了解一下《操作系统》对于死锁产生条件的描述。
死锁产生的条件:
互斥条件:所谓互斥就是进程在某一时间内独占资源。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
死锁的例子
public class Test {
public static void main(String[] args) {
DeadlockRisk dead = new DeadlockRisk();
MyThread t1 = new MyThread(dead, 1, 2);
MyThread t2 = new MyThread(dead, 3, 4);
MyThread t3 = new MyThread(dead, 5, 6);
MyThread t4 = new MyThread(dead, 7, 8);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class MyThread extends Thread {
private DeadlockRisk dead;
private int a, b;
MyThread(DeadlockRisk dead, int a, int b) {
this.dead = dead;
this.a = a;
this.b = b;
}
@Override
public void run() {
dead.read();
dead.write(a, b);
}
}
class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized (resourceA) {
System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceA的锁!");
synchronized (resourceB) {
System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceB的锁!");
return resourceB.value + resourceA.value;
}
}
}
public void write(int a, int b) {
synchronized (resourceB) {
System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceA的锁!");
synchronized (resourceA) {
System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceB的锁!");
resourceA.value = a;
resourceB.value = b;
}
}
}
}
//运行结果
read():Thread-0获取了resourceA的锁!
read():Thread-0获取了resourceB的锁!
write():Thread-0获取了resourceA的锁!
read():Thread-3获取了resourceA的锁!
获取线程dump
jps获得当前Java虚拟机进程的pid
➜ ~ jps
657
2564 Jps
2525 AppMain
2526 Launcher-
jstack打印堆栈
Found one Java-level deadlock:
=============================
"Thread-3":
waiting to lock monitor 0x00007fd5ca80c368 (object 0x00000007d56d1550, a deadlock.DeadlockRisk$Resource),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007fd5ca80ed58 (object 0x00000007d56d1540, a deadlock.DeadlockRisk$Resource),
which is held by "Thread-3"Java stack information for the threads listed above: =================================================== "Thread-3": at deadlock.DeadlockRisk.read(Test.java:52) - waiting to lock <0x00000007d56d1550> (a deadlock.DeadlockRisk$Resource) - locked <0x00000007d56d1540> (a deadlock.DeadlockRisk$Resource) at deadlock.MyThread.run(Test.java:35) "Thread-0": at deadlock.DeadlockRisk.write(Test.java:62) - waiting to lock <0x00000007d56d1540> (a deadlock.DeadlockRisk$Resource) - locked <0x00000007d56d1550> (a deadlock.DeadlockRisk$Resource) at deadlock.MyThread.run(Test.java:36) Found 1 deadlock.
更多关于线程dump可以参考:http://my.oschina.net/u/161458/blog/266313
如何避免死锁
避免一个线程同时获取多个锁。
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
活锁
活锁:马路中间有条小桥,只能容纳一辆车经过,桥两头开来两辆车A和B,A比较礼貌,示意B先过,B也比较礼貌,示意A先过,结果两人一直谦让谁也过不去。