(本文为廖雪峰java学习笔记)
能被同一个线程反复获取的锁叫做可重入锁。
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;
}
}
在n<0分支里dec(-n)方法可以执行下去,因为JVM允许同一个线程重复获取同一个锁,每获取一次锁,记录+1,每退出synchronized块,记录-1,减到0的时候,才会真正释放锁。
什么是死锁?多个线程互相等待对方释放持有的资源就会造成死锁。比如下面代码,如果两个线程分别执行add和dec方法则会造成死锁。
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的锁
}
避免死锁的方法是,线程获取锁的顺序要一致。上面的代码按如下改则可以避免死锁(方法add和dec获取锁的顺序都一样):
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) { // 获得lockA的锁
this.another -= m;
synchronized(lockB) { // 获得lockB的锁
this.value -= m;
} // 释放lockB的锁
} // 释放lockA的锁
}