手写自旋等待,解决死锁问题

说明:本文介绍如何写自旋逻辑,解决死锁问题。

死锁问题

死锁,指多个进程都在等对方释放资源,才能继续执行,以致进程阻塞。


产生死锁有以下四个必要条件:

  • 互斥条件:进程获取的资源具有排他性。“我拿了,别人就拿不了”

  • 请求与保持:进程获取到资源,后进程阻塞,不会释放已有资源。“我拿了,不做完事情,我就不放下”

  • 不可剥夺:进程获取到资源,其他进程不可强制剥夺。“我拿在手上,别人抢不走”

  • 循环等待:进程没有获取到所需资源,会持续等待,最终产生了死锁。“你等我,我等他,他等你”


如何避免死锁,只需破坏必要条件中的一个即可,如:

  • 互斥条件:锁的作用就是让进程前互斥,这个条件没法破坏,用锁作用就是这个,除非不用锁,不用锁也就不存在死锁问题。

  • 请求与保持:让进程一次性申请到所有资源,即将进程所需的所有资源打包成一个。

  • 不可剥夺:进程获取资源,进一步申请其他资源时,如果申请不到,要求进程主动释放已有资源。

  • 循环等待:申请资源按照顺序申请,释放资源按照逆序释放,目的是保证任何时间都不会有进程持有非顺序的资源,就是说,争抢下个资源的前提是已获取到所需的资源。

场景

博主之前遇到过一个问题,在DAO访问数据库这里,产生了死锁

        orderDetailRepository.updateOrder(orderId, status);

该操作是一个更新多条数据库记录的操作,而这张表是一张记录流水的表,会频繁写入数据,博主猜想可能是两个进程,一个写入,一个更新,产生了死锁。

自旋

后通过自旋等待,解决了此问题(进程争抢资源都是毫秒级别的,死锁问题很罕见,加入自旋等待后就没出现过问题了,我也无法确定问题是否解决)

如下:

        // 这里可能出现死锁,如果出现死锁,自旋重试
        // 初始重试次数
        int retryCount = 3;
        // 初始等待时间(毫秒)
        int sleepTime = 100;
        while (retryCount > 0) {
            try {
                orderDetailMapper.updateOrder(orderId, status);
                break;
            } catch (DeadlockLoserDataAccessException e) {
                retryCount--;
                if (retryCount == 0) {
                    throw e;
                }
                // 记录死锁日志
                log.warn("产生死锁, 等待重试... 重试次数: {}", retryCount);
                try {
                    TimeUnit.MILLISECONDS.sleep(sleepTime);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
                // 每次等待时间翻倍
                sleepTime *= 2;
            }
        }

总结

本文介绍项目中产生进程死锁,手写自旋进程等待,解决死锁问题的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何中应

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值