(也就是整个程序都满足上述的四个条件)
<0>分析与解释。
- "死锁类"不采用实现Runnable接口,重新run()方法。而是在测试中直接使用匿名的Runnable实现子类。()->{}。中括号里面就是实现的run()方法。
- "死锁类"创建的两个类的锁对象(static)。在该"死锁"类的new两个即可。保证a与b"锁"是这个"死锁类"是共享的。
- 测试类中到时候模拟两个线程,同时new两个"死锁"类的对象。d1、d2是不共享的,但是锁a、锁b是共享的资源。
- 测试类中的new Thread(Runnable target)。参数内部是使用Lambda表达式(也可以使用匿名内部类)也就是在重新的run()方法里面进行调用方法操作(d1.执行死锁方法、d2.执行死锁方法)
- 测试类中最后两个线程分别去使用start()方法。然后分别去拿各自的"锁a"、"锁b",然后阻塞(哈哈哈!)
- "死锁类"中这里注意还需要有一个布尔类型的变量。去控制获取锁的顺序。顺序????就是为"true"时控制一个线程拿"锁"时,从a锁——>b锁。值为false时让另外一个线程拿"锁"时,从b锁——>a锁。flag不是设置成共享的(不是static)。
(具体详细代码如下。)
<1>简单死锁程序(类DeadLockDemo)
package com.fs;
/**
* @Title: DeadLockDemo
* @Author HeYouLong
* @Package com.fs
* @Date 2024/10/12 下午8:41
* @description: 简单死锁程序演示
*/
public class DeadLockDemo {
//锁a与锁b
private static Object a = new Object();
private static Object b = new Object();
//控制拿锁的顺序,a——>b或者b——>a
private boolean flag;
//提供构造方法改布尔值
public DeadLockDemo(boolean flag) {
this.flag = flag;
}
public void testDeadLock() throws InterruptedException {
if(flag){
//a——>b
synchronized (a){
System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
synchronized (b){
System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
}
}
}else {
//b——>a
synchronized (b){
System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
synchronized (a){
System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
}
}
}
}
}
<2>测试类(Test)
package com.fs;
/**
* @Title: Test
* @Author HeYouLong
* @Package com.fs
* @Date 2024/10/13 上午10:59
* @description: 测试类
*/
public class Test {
public static void main(String[] args) {
//创建不同对象
DeadLockDemo d1 = new DeadLockDemo(true);
DeadLockDemo d2 = new DeadLockDemo(false);
Thread t1 = new Thread(()->{
//线程t1的run()方法使用d1对象
//但是在对象调用testDeadLock()使用的是共享资源的锁
try {
d1.testDeadLock();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"线程1");
Thread t2 = new Thread(()->{
//线程t2的run()方法使用d2对象
// 但是在对象调用testDeadLock()使用的是共享资源的锁
try {
d2.testDeadLock();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"线程2");
//启动线程
t1.start();
t2.start();
}
}
<3>程序执行结果。(发生"死锁")
<4>破坏上面的"简单死锁程序"。
(I)破坏互斥条件。
(II)破坏不可抢占条件。
(III)破坏请求和保持条件。
- 让两个线程"t1"、"t2"都执行完资源后释放完各自的"锁",然后再去申请其它"锁"。(不允许它保持)
public void testDeadLock() throws InterruptedException {
if(flag){
//a——>b
synchronized (a){
System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
}
synchronized (b){
System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
}
}else {
//b——>a
synchronized (b){
System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
}
synchronized (a){
System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");
Thread.sleep(100); //模拟执行完后等待
}
}
}
(IIII)破坏循环等待条件。
- 简单修改即可。不让他们请求锁时形成环路。(把顺序都变成"锁a"——>"锁b")