问题重现
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
// 这里会造成 嵌套 获取 对方的锁
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend zhangsan = new Friend("张三");
final Friend lisi = new Friend("李四");
// 线程thread1先获取zhangsan的锁,然后在同步块里嵌套竞争锁lisi的锁
// 此时已经被线程thread2拥有,而thread2在等待zhangsan的锁
new Thread(new Runnable() {
public void run() {
zhangsan.bow(lisi);
}
}).start();
// 而thread2先获取lisi的锁,然后在同步块里嵌套竞争锁zhangsan的锁
// 此时已经被线程thread1拥有,而thread1在等待李四的锁
new Thread(new Runnable() {
public void run() {
lisi.bow(zhangsan);
}
}).start();
}
}
解决方式
用ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;
/**
* 用 reentrantLock解决死锁问题
* 使用reentrantLock显示锁 和 通过使用synchronized同步代码的方式使用 隐式锁基本上是一样的;
* (一) 一样的地方
* 1.同一线程在同一时间 只能拥有一个Lock对象
* 2.Lock对象,也同样支持wait/notify机制,因为内部可以返回Condition接口对象,具体是Condition newCondition()方法
* (二) 优势,不同点
* 1.Lock对象有能力在获取锁的时候返回,而不是阻塞在那里(比如用synchronized),如果对象没有锁可以使用,就会立马返回
* @author TreeNode
*
*/
public class Safelock {
static class Friend {
private final String name;
private final Lock lock = new ReentrantLock();
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public boolean impendingBow(Friend bower) {
Boolean myLock = false;
Boolean yourLock = false;
try {
// 试着去获取锁,占用着返回false
myLock = lock.tryLock();
yourLock = bower.lock.tryLock();
} finally {
if (!(myLock && yourLock)) {
if (myLock) {
lock.unlock();
}
if (yourLock) {
bower.lock.unlock();
}
}
}
return myLock && yourLock;
}
public void bow(Friend bower) {
if (impendingBow(bower)) {
try {
System.out.format("%s: %s has" + " bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
} finally {
lock.unlock();
bower.lock.unlock();
}
} else {
System.out.format("%s: %s started" + " to bow to me, but saw that"
+ " I was already bowing to" + " him.%n", this.name, bower.getName());
}
}
public void bowBack(Friend bower) {
System.out.format("%s: %s has" + " bowed back to me!%n", this.name, bower.getName());
}
}
static class BowLoop implements Runnable {
private Friend bower;
private Friend bowee;
public BowLoop(Friend bower, Friend bowee) {
this.bower = bower;
this.bowee = bowee;
}
public void run() {
Random random = new Random();
for (;;) {
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
}
bowee.bow(bower);
}
}
}
public static void main(String[] args) {
final Friend zhangsan = new Friend("张三");
final Friend lisi = new Friend("李四");
new Thread(new BowLoop(zhangsan, lisi)).start();
new Thread(new BowLoop(lisi, zhangsan)).start();
}
}