1.死锁的概念:多个线程在运行过程中因争夺资源而造成的一种相互获取锁,但获取不到所的僵局。
例子:小明玩篮球,小张玩足球,然后小明想玩足球,小张想玩篮球,但此时小张占有足球不放弃资源,小张想玩篮球,小明也不放弃资源,造成小明和小张僵持的局面,造成死锁。
用code实现如下:
package DeadLock1;
public class DeadLock {
private static Object basketball = new Object();
private static Object football = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(()->{
synchronized (basketball) {
System.out.println("小明获得篮球,想要足球");
synchronized (football) {
System.out.println("小明获得了足球!!");
}
}
} );
Thread thread2 = new Thread(()-> {
synchronized (football) {
System.out.println("小张获得足球,想要篮球");
synchronized (basketball) {
System.out.println("小张获得了篮球");
}
}
}) ;
thread1.start();
thread2.start();
}
}
展示死锁示意图:
2.死锁检测
死锁一般在代码运行的过程中是不会报错的,所以通过log和code是很难知道因死锁而导致程序的崩溃。有检测工具进行检测死锁。
方法一:执行jps-->jstack-->可以看到log
在此记录一个遇到的坑,我直接windows+r-->cmd直接执行jps,出现jps不是内部命令,因为我刚开始的时候配置的jdk没有jps的命令,直接找到bin去执行jps.
方法二:使用命令jConsole能调出可视化工具
3.死锁的解决方式
方式一:严格控制获取锁的顺序
package DeadLock1;
public class DeadLock {
private static Object basketball = new Object();
private static Object football = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(()->{
synchronized (basketball) {
System.out.println("小明获得篮球,想要足球");
synchronized (football) {
System.out.println("小明获得了足球!!");
}
}
} );
Thread thread2 = new Thread(()-> {
synchronized (basketball) {
System.out.println("小张获得足球,想要篮球");
synchronized (football) {
System.out.println("小张获得了篮球");
}
}
}) ;
thread1.start();
thread2.start();
}
}
方法二:超时放弃
一般采用方法一,超时放弃是利用了Lock提供的boolean tryLock(long time, TimeUnit unit) throws InterruptedException ,此方法可以按照固定的时长等待锁,因此线程可以在获取锁超时以后,主动释放之前已经获得的所有锁。