死锁

当一个线程永远地持有一个锁,并且其他线程都尝试去获得这个锁时,那么它们将永远被阻塞,这个我们都知道。如果线程A持有锁L并且想获得锁M,线程B持有锁M并且想获得锁L,那么这两个线程将永远等待下去,这种情况就是最简单的死锁形式。

在数据库系统的设计中考虑了监测死锁以及从死锁中恢复,数据库如果监测到了一组事物发生了死锁时,将选择一个牺牲者并放弃这个事物。Java虚拟机解决死锁问题方面并没有数据库这么强大,当一组Java线程发生死锁时,这两个线程就永远不能再使用了,并且由于两个线程分别持有了两个锁,那么这两段同步代码/代码块也无法再运行了—-除非终止并重启应用。

死锁是设计的BUG,问题比较隐晦。不过死锁造成的影响很少会立即显现出来,一个类可能发生死锁,并不意味着每次都会发生死锁,这只是表示有可能。当死锁出现时,往往是在最糟糕的情况—-高负载的情况下。


下面给出一个产生死锁的简单代码并且演示如何分析这是一个死锁:

package com.mook.deadLock;

public class DeadLock
{
    private final Object left = new Object();
    private final Object right = new Object();

    public void leftRight() throws Exception
    {
        synchronized (left)
        {
            Thread.sleep(2000);
            synchronized (right)
            {
                System.out.println("leftRight end!");
            }
        }
    }

    public void rightLeft() throws Exception
    {
        synchronized (right)
        {
            Thread.sleep(2000);
            synchronized (left)
            {
                System.out.println("rightLeft end!");
            }
        }
    }
}
package com.mook.deadLock;

public class Thread0 extends Thread
{
    private DeadLock dl;

    public Thread0(DeadLock dl)
    {
        this.dl = dl;
    }

    public void run()
    {
        try
        {
            dl.leftRight();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
package com.mook.deadLock;

public class Thread1 extends Thread
{
    private DeadLock dl;

    public Thread1(DeadLock dl)
    {
        this.dl = dl;
    }

    public void run()
    {
        try
        {
            dl.rightLeft();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
package com.mook.deadLock;

public class Test {
    public static void main(String[] args)
    {
        DeadLock dl = new DeadLock();
        Thread0 t0 = new Thread0(dl);
        Thread1 t1 = new Thread1(dl);
        t0.start();
        t1.start();

        while(true);
    }
}

至于结果,没有结果,什么语句都不会打印,因为死锁了。下面演示一下如何定位死锁问题:
1、jps获得当前Java虚拟机进程的pid
jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有Java进程pid的命令
这里写图片描述
其中AppMain就是该程序运行的java进程

2、jstack打印堆栈。
jstack打印内容的最后其实已经报告发现了一个死锁
这里写图片描述


避免死锁的方式

既然可能产生死锁,那么接下来,讲一下如何避免死锁。

1、让程序每次至多只能获得一个锁。当然,在多线程环境下,这种情况通常并不现实

2、设计时考虑清楚锁的顺序,尽量减少嵌在的加锁交互数量

3、既然死锁的产生是两个线程无限等待对方持有的锁,那么只要等待时间有个上限不就好了。当然synchronized不具备这个功能,但是我们可以使用Lock类中的tryLock方法去尝试获取锁,这个方法可以指定一个超时时限,在等待超过该时限之后变回返回一个失败信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值