可重入锁:
public class Counter {
private int count = 0;
public synchronized void add(int n) {
if (n < 0) {
dec(-n);
} else {
count += n;
}
}
public synchronized void dec(int n) {
count += n;
}
}
上述例子中,add()方法获取到this锁,调用dec()方法,dec()方法能否获取到this锁?答案是肯定的,这就是Java中的可重入锁。但要注意,在获取锁时要判断是第几次获取,并记下第几次,退出时每次减一,知道为0才能完全退出。
死锁
当两个代码块争用同一资源时,会发生死锁。
public void add(int m) {
synchronized(lockA) { // 获得lockA的锁
this.value += m;
synchronized(lockB) { // 获得lockB的锁
this.another += m;
} // 释放lockB的锁
} // 释放lockA的锁
}
public void dec(int m) {
synchronized(lockB) { // 获得lockB的锁
this.another -= m;
synchronized(lockA) { // 获得lockA的锁
this.value -= m;
} // 释放lockA的锁
} // 释放lockB的锁
}
对于上述代码,线程1和线程2如果分别执行add()和dec()方法时:
- 线程1:进入add(),获得lockA;
- 线程2:进入dec(),获得lockB。
然后:
- 线程1:准备获得lockB,失败,等待中;
- 线程2:准备获得lockA,失败,等待中。
这就陷入死锁状态。
Java中解决死锁的方法是:
public void add(int m) {
synchronized(lockA) { // 获得lockA的锁
this.value += m;
synchronized(lockB) { // 获得lockB的锁
this.another += m;
} // 释放lockB的锁
} // 释放lockA的锁
}
public void dec(int m) {
synchronized(lockA) { // 获得lockB的锁
this.value -= m;
synchronized(lockB) { // 获得lockA的锁
this.another -= m;
} // 释放lockA的锁
} // 释放lockB的锁
}
获取资源的顺序相同,即在本例中获取锁的顺序相同,先获取A锁,再获取B锁。