一个线程如果需要同时获取多把锁,就容易产生死锁。
t1线程获得A对象锁,接下来想获取B对象的锁。
t2线程获得B对象锁,接下来想获取A对象的锁。
/**
* 死锁demo
* @param args
*/
public static void main(String[] args) {
Object a = new Object();
Object b = new Object();
new Thread(() -> {
synchronized (a) {
log.info("lock a");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
log.info("lock b...");
}
}
}, "t1").start();
new Thread(() -> {
synchronized (b) {
log.info("lock b");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
log.info("lock a...");
}
}
}).start();
}
使用工具定位死锁:
cmd下的jps命令,可以查看当前正在运行的java进程
工具一:jstack命令
可以定位到具体的代码行数:
工具二:jconsole
经典死锁案例:五位哲学家五根筷子吃饭
public class DeadLockDemo {
public static void main(String[] args) {
Chopstick chopstick1 = new Chopstick("1");
Chopstick chopstick2 = new Chopstick("2");
Chopstick chopstick3 = new Chopstick("3");
Chopstick chopstick4 = new Chopstick("4");
Chopstick chopstick5 = new Chopstick("5");
new Philosopher("哲学家1", chopstick1, chopstick2).start();
new Philosopher("哲学家2", chopstick2, chopstick3).start();
new Philosopher("哲学家3", chopstick3, chopstick4).start();
new Philosopher("哲学家4", chopstick4, chopstick5).start();
new Philosopher("哲学家5", chopstick5, chopstick1).start();
}
}
@Slf4j
class Philosopher extends Thread {
//左边的筷子
Chopstick left;
//右边的筷子
Chopstick right;
public Philosopher(String name, Chopstick left, Chopstick right) {
super(name);//设置线程名称
this.left = left;
this.right = right;
}
@Override
public void run() {
while (true) {//这里意思是一位哲学家获取了两根筷子后吃完饭,又重新开始下一轮...
synchronized (left) {
synchronized (right) {
eat();
}
}
}
}
private void eat() {
log.info("eat...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 筷子类
*/
class Chopstick {
//名称
private String name;
public Chopstick(String name) {
this.name = name;
}
@Override
public String toString() {
return "Chopstick{" +
"name='" + name + '\'' +
'}';
}
}