目录
死锁:
线程执行的时候由于获取不到锁资源造成的程序卡死状态
死锁场景:
1.单线程获取一把锁:
一个线程多次(两次以上)获取同一把锁,造成死锁(前提该锁为非可重入锁)。
2.两个线程获取同两把锁:
第一个线程的锁被第二个线程持有,第二个线程的锁被第一个线程持有,造成死锁。
import java.util.concurrent.TimeUnit;
/**
* 两个线程两把锁
*/
public class DeadLock_Demo01 {
public static void main(String[] args) {
Object locker1 = new Object();
Object locker2 = new Object();
Thread thread1 = new Thread(()->{
System.out.println("t1申请锁资源");
synchronized (locker1){
System.out.println("t1获取了第一把锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (locker2){
System.out.println("t1获取了第二把锁");
}
}
});
Thread thread2 = new Thread(()->{
System.out.println("t2申请锁资源");
synchronized (locker2){
System.out.println("t2获取了第二把锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (locker1){
System.out.println("t2获取了第一把锁");
}
}
});
thread1.start();
thread2.start();
}
}
3.多个线程获取多把锁:
举例:有三个线程,分别只能打印A,B和C * 要求按顺序打印ABC,打印10次。思路:创建三把锁,线程1获取第一把锁,打印A成功后唤醒第二把锁,线程2获取第二把锁,打印B成功后唤醒第三把锁,线程3获取第三把锁打印C成功后唤醒第一把锁,不加干预的情况下,会陷入三个线程互相等待唤醒的死锁状态。
/**
* 有三个线程,分别只能打印A,B和C
* 要求按顺序打印ABC,打印10次
* 输出示例:
* ABC
* ABC
* ABC
* ABC
* ABC
* ABC
* ABC
* ABC
* ABC
* ABC
*/
public class FirstCode {
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Object lock2 = new Object();
Object lock3 = new Object();
Thread threadA = new Thread(()->{
try {
for(int i = 0; i < 10; i++){
synchronized (lock1){
lock1.wait();
}
System.out.print("A");
synchronized (lock2){
lock2.notify();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Thread threadB = new Thread(()->{
try {
for(int i = 0; i < 10; i++){
synchronized (lock2){
lock2.wait();
}
System.out.print("B");
synchronized (lock3){
lock3.notify();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Thread threadC = new Thread(()->{
try {
for(int i = 0; i < 10; i++){
synchronized (lock3){
lock3.wait();
}
System.out.println("C");
synchronized (lock1){
lock1.notify();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
threadC.start();
threadA.start();
threadB.start();
//这段代码不加就造成死锁
//Thread.sleep(1000);
//synchronized (lock1){
// lock1.notify();
//}
}
}
死锁成因:
1.互斥访问:线程一拿到了锁,线程二就不能同时获取同一把锁。
2.不可抢占:获取到锁的线程在自己不主动释放锁的情况下,其他线程无法抢占锁资源。
3.请求与保持:在线程一获取了一把锁后,还要继续获取第二把另外的锁。
4.循环等待:线程一等待线程二,线程二等待线程三,线程三等待线程一。
死锁解决方案:
1.互斥访问:锁特性无法打破。
2.不可抢占:锁特性无法打破。
3.请求与保持:改变获取锁的顺序。
4.循环等待:设计一套获取锁的策略,或其他方式来强制唤醒其中一个线程打破循环(如上代码末尾注释所示)