Java多线程死锁案例及分析

1.什么是死锁

  1. 主线程拥有a对象的锁,并试图获取b对象的锁;
  2. 副线程拥有b对象的锁,并试图获取a对象的锁;
  3. 大家谁都不释放,OK,场面僵住了,死锁出现了;

2.Demo

/**
 * @version V1.0
 * @ClassName:DeadLockTest
 * @Description: 死锁测试
 * @author:Daniel
 * @date:2020/11/28 下午9:37
 */
public class DeadLockTest implements Runnable{
    
    
    A a = new A();
    B b = new B();

    public void init() {
    
    
        Thread.currentThread().setName("主线程");
        // 调用a对象的foo()方法
        a.foo(b);
        System.out.println("进入了主线程后");
    }


    @Override
    public void run() {
    
    
        Thread.currentThread().setName("副线程");
        // 调用b对象的bar方法
        b.bar(a);
        System.out.println("进入了副线程之后");
    }

    public static void main(String[] args) {
    
    
        DeadLockTest d1 = new DeadLockTest();
        new Thread(d1).start();
        d1.init();
    }
}


class A {
    
    
    public synchronized void foo(B b) {
    
    
        System.out.println("当前线程名:" + Thread.currentThread().getName() + " 进入了A实例的foo()方法");
        try {
    
    
            Thread.sleep(200);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("当前线程名:" + Thread.currentThread().getName() + " 试图进入B实例的last()方法");
        b.last();
    }


    public synchronized void last() {
    
    
        System.out.println("当前线程名: " + Thread.currentThread().getName() + " 进入了A实例的 last() 方法 ");
    }
}


class B {
    
    
    public synchronized void bar(A a) {
    
    
        System.out.println("当前线程名:" + Thread.currentThread().getName() + " 进入了B实例的bar()方法");
        try {
    
    
            Thread.sleep(200);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("当前线程名:" + Thread.currentThread().getName() + " 试图进入A实例的last()方法");
        a.last();
    }


    public synchronized void last() {
    
    
        System.out.println("当前线程名: " + Thread.currentThread().getName() + " 进入了B实例的 last() 方法 ");
    }
}

运行结果:
在这里插入图片描述

3. 解释

  • 程序中有两个线程执行,副线程的线程执行体是DeadLock类run( )方法,主线程的线程执行体是DeadLock的main( )方法(主线程调用了init()方法)。
  • 其中run()方法中让B对象调用bar()方法,而init( )方法让A对象调用foo( )方法。
  • 结果显示init( )方法先执行,调用了A对象的foo( )方法,进入foo( )方法前,该线程对A对象加锁,执行到sleep( )时,主线程暂停200ms;CPU切换到执行另一个线程。让B对象执行bar( )方法,所以看到副线程开始执行B实例的bar()方法,进入bar( ) 方法之前,该线程对B对象加锁,当执行到sleep(),副线程也暂停200ms
  • 接下来,主线程会先醒过来,继续向下执行,执行last( )方法之前,必须先对B对象加锁,但此时副线程正保持着B对象的锁,所以主线程阻塞;
  • 接下来,副线程醒过来,向下执行,执行last( )方法之前必须先对A对象加锁,但此时主线程没有释放A对象的锁;
  • 至此,就出现了主线程保持着A对象的锁,等待对B对象加锁,而副线程保持着B对象的锁,等待对A对象加锁,两个线程相互等待对方先释放,就出现了死锁。

猜你喜欢

转载自blog.csdn.net/DDDDeng_/article/details/110294843