多线程系列(五) -死锁分析及解决办法介绍

一、简介

在之前的文章中,我们介绍了synchronized同步锁关键字的作用以及相关的用法,它能够保证同一时刻最多只有一个线程执行修饰的代码段,以实现线程安全执行的效果

但是如果过度的使用synchronized等方式进行加锁,程序可能会出现死锁现象。

那什么是死锁呢?它有什么危害?

我们知道被synchronized修饰的代码,当一个线程持有一个锁,其它线程尝试去获取这个锁未获取到时,那么其它线程会进入阻塞状态,直到线程释放锁才能再次拥有获取锁的条件。假如线程 A 持有锁 L 并且想获取锁 R,线程 B 持有锁 R 并且想获取锁 L,那么这两个线程将会永久等待下去,这种情况就是最简单的死锁现象。

如果程序出现了死锁,会给系统功能带来非常严重的问题,轻则导致程序响应时间变长,系统吞吐量变小;重则导致应用中的某一个功能直接失去响应能力无法提供服务,因此我们应该及时发现并避规这些问题。

当然发生死锁的软件应用,不仅限于 Java 程序,还有数据库等,不同的是:数据库系统中设计了死锁的检测以及从死锁中恢复的机制,数据库如果检测到一组事务中发生了死锁,将选择一个牺牲者并放弃这个事务。

而 Java 虚拟机解决死锁问题并没有数据库那么强大,在 Java 程序中,采用synchronized加锁的代码如果发生死锁,两个线程就不能再使用了,并且这两个线程所在的同步代码/代码块也无法再运行了,除非杀掉服务,然后重启服务!

在实际的软件项目开发过程中,死锁其实是编程设计上的 bug,问题也比较隐晦,即使通过压力测试也不一定能找到程序上的死锁问题。死锁的出现,往往是在高负载的情况下产生,这种场景下比较难定位。

二、死锁复现

下面我们先来看一个比较经典的产生死锁示例代码。

public class DeadLock {
   

    private final Object right = new Object();

    private final Object left = new Object();

    /**
     * 加锁顺序从left -> right
     */
    public void leftRight() throws Exception {
   
        synchronized (left) {
   
            // 模拟某个业务操作耗时
            Thread.sleep(1000);
            synchronized (right
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值