多线程死锁

        Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。在多线程技术中,“死锁”是必须要避免的,因为这会造成线程的“假死”。

下面我们来看一个具体的死锁示例:

@Test
public void testDeadLock() {
    Object lockA = new Object();
        Object lockB = new Object();
        B14PrinterService service = new B14PrinterService(lockA, lockB);
        Thread aThread = new B14PrinterAThread(service);
        aThread.setName("ThreadA");
        Thread bThread = new B14PrinterBThread(service);
        bThread.setName("ThreadB");
        aThread.start();
        bThread.start();
        try {
            aThread.join();
            bThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

class B14PrinterAThread extends Thread {

    private B14PrinterService service;

    public B14PrinterAThread(B14PrinterService service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.printA();
    }
}

class B14PrinterBThread extends Thread {

    private B14PrinterService service;

    public B14PrinterBThread(B14PrinterService service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.printB();
    }
}

class B14PrinterService {

    private Object lockA;

    private Object lockB;

    public B14PrinterService(Object lockA, Object lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    public void printA() {
        synchronized (lockA) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("[" + Thread.currentThread().getName() + "] print A");
            synchronized (lockB) {
                System.out.println("[" + Thread.currentThread().getName() + "] print B");
            }
        }
    }

    public void printB() {
        synchronized (lockB) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("[" + Thread.currentThread().getName() + "] print B");
            synchronized (lockA) {
                System.out.println("[" + Thread.currentThread().getName() + "] print A");
            }
        }
    }
}

        在上面的这个demo中,开启了ThreadA,ThreadB两个线程,其中ThreadA首先占用了lockA对象锁,并等待ThreadB释放lockB对象锁。而线程ThreadB则先占用了lockB对象锁,并等待ThreadA释放lockA对象锁,造成了ThreadA和ThreadB出现了死锁问题。

        我们通过jps和jstack来证明这种推论:

通过jps命令来查看当前主机的运行的java进程,找到当前死锁的Java进程的进程号:54462。

通过 jstack 进程号 来查看当前死锁情况,可以看出 ThreadB 在等待一个lock,而这个锁正在被 ThreadA 所持有,而 ThreadA 也在等待一个lock,而这个锁也正在被 ThreadB 所持有,所以就产生了死锁的情况发生。

   死锁是程序设计的BUG,在设计程序时就要避免双方互相持有对方的锁的情况。需要说明的是,本实验使用synchronized嵌套的代码结构来实现死锁,其实不使用嵌套的synchronized代码结构也会出现死锁,与嵌套不嵌套无任何关系,不要被代码结构所误导。只要互相等待对象释放锁就有可能出现死锁。

那么,通常可以用如下方式避免死锁的情况:

1、避免一个线程同时获得多个锁;

2、避免一个线程在锁内部占用多个资源,尽量保证每个锁只占用一个资源;

3、尝试使用定时锁,使用lock.tryLock(timeOut),当超时等待时当前线程不会阻塞;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值