一、死锁产生条件
- 互斥条件:一个线程只能被一个线程使用。
- 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持一致不变
- 不剥夺条件:线程已获得的资源,在未使用完之前,不强行剥夺。
- 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
典型的三种死锁类型:1.静态的顺序死锁;2.动态的顺序死锁;3.协作对象之间发生的死锁。
二、静态的顺序死锁
一下是错误写法例子,可能造成顺序死锁
public static void main(String[] args) {
StaticLockOrderDeadLock lock = new StaticLockOrderDeadLock();
while (true){
new Thread(new Runnable() {
@Override
public void run() {
lock.a();
lock.c();
}
}).start();
}
}
class StaticLockOrderDeadLock {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void a() {
synchronized (lockA) {
synchronized (lockB) {
System.out.println("function a");
}
}
}
public void b() {
synchronized (lockB) {
synchronized (lockA) {
System.out.println("function b");
}
}
}
}
所有需要多个锁的线程,都需要以相同顺序来获得锁。
以下是正确写法例子
public class DeadLock {
public static void main(String[] args) {
StaticLockOrderDeadLock lock = new StaticLockOrderDeadLock();
while (true){
new Thread(new Runnable() {
@Override
public void run() {
lock.a();
lock.b();
}
}).start();
}
}
}
class StaticLockOrderDeadLock {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void a() {
synchronized (lockA) {
synchronized (lockB) {
System.out.println("function a");
}
}
}
public void c() {
synchronized (lockB) {
synchronized ( lockA) {
System.out.println("function c");
}
}
}
public void b() {
synchronized (lockA) {
synchronized (lockB) {
System.out.println("function b");
}
}
}
}
三、动态的顺序死锁
动态的锁顺序死锁是指两个线程调用同一个方法时,传入的参数调到造成的死锁。
new Thread(new Runnable() {
@Override
public void run() {
try {
lock.transefMoney(new Account(100), new Account(200), 200);
} catch (InsufficientResourcesException e) {
e.printStackTrace();
}
}
}).start();
public void transefMoney(Account fromAccount, Account toAccount, double amount) throws InsufficientResourcesException {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.compareTo(amount) < 0) {
throw new InsufficientResourcesException();
} else {
toAccount.debit(amount);
fromAccount.credit(amount);
}
}
}
}
输出结果:
javax.naming.InsufficientResourcesException
at DynamicLockOrderDeadLock.transefMoney(DeadLock.java:35)
at DeadLock$1.run(DeadLock.java:15)
at java.lang.Thread.run(Thread.java:748)
class Account implements Comparable {
String userName;
String password;
double moneyCount;
/**
* 取款
*
* @param amount
*/
public void debit(double amount) {
moneyCount -= amount;
System.out.println(moneyCount);
}
public void credit(double amount) {
moneyCount += amount;
System.out.println(moneyCount);
}
@Override
public int compareTo(Object o) {
return (int) (moneyCount - ((double) o));
}
}
动态死锁解决方法:使用Sysem.identifyHashCode来定义锁的顺序
new Thread(new Runnable() {
@Override
public void run() {
Account fromAccount = new Account();
lock.transferMoney2(fromAccount, fromAccount, 200);
}
}).start();
public void transferMoney2(Account fromAccount, Account toAccount, double amount) {
class Helper {
public void transfer() {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
int fromHash = System.identityHashCode(fromAccount);
int toHash = System.identityHashCode(toAccount);
if (fromHash < toHash) {
synchronized (fromAccount) {
synchronized (toAccount) {
new Helper().transfer();
}
}
} else if (fromHash > toHash) {
synchronized (toAccount) {
synchronized (fromAccount) {
new Helper().transfer();
}
}
} else {
synchronized (obj){
synchronized (fromAccount){
synchronized (toAccount){
new Helper().transfer();
}
}
}
}
}