一个线程如果需要同时获取多把锁,就容易产生死锁。
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;}@Overridepublic 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;}@Overridepublic String toString() {return "Chopstick{" +"name='" + name + '\'' +'}';}
}