手写死锁demo

代码实现:
class HoldLockThread implements Runnable{
    private String lockA;
    private String lockB;

    public HoldLockThread(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    @Override
    public void run() {
        synchronized (lockA) {
            System.out.println(lockB);  //持有lockA、尝试获取lockB
            synchronized (lockB) {
                System.out.println(lockA);  //持有lockB、尝试获取lockA
            }
        }
    }
}
public class DeadLockDemo {
    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";
        new Thread(new HoldLockThread(lockA, lockB)).start();
        new Thread(new HoldLockThread(lockB, lockA)).start();
    }
}

### 死锁问题分析 在多线程环境中,死锁是指两个或更多线程互相持有对方所需的资源而无限期地等待的情况。具体来说,当一组进程中的每一个都在等待仅由该组中其他进程持有的资源被释放时发生死锁。 #### 导致死锁的四个必要条件 1. **互斥条件** - 至少有一个资源必须处于不可抢占状态;即一旦一个线程获得了某个资源,则它不能同时被另一个线程所拥有。 2. **占有并请求(Hold and Wait)** - 进程已经持有了至少一种类型的资源,并正在申请新的资源,但是这些新资源已经被其他的进程占用着[^1]。 3. **非剥夺条件** - 已分配给进程的资源只能由该进程自行释放,而不能被其他任何进程强行夺取。 4. **环路等待条件** - 存在一个涉及所有进程中每个成员的封闭回路,其中每个进程都正等待下一个进程拥有的资源。 ### 解决方案 为了防止死锁的发生,可以采取以下几种策略: - **破坏“占有并请求”条件** 让所有的线程要么一开始就获取它们所需的所有锁,要么完全不获取任何一个锁。这可以通过提前声明所有可能需要访问的数据结构来实现。例如,在初始化阶段就锁定整个数据集而不是逐步增加锁定范围。 - **采用超时机制** 如果一个线程未能成功获得必要的资源超过一定时间间隔,则放弃当前操作并重试。这种方法能够有效打破长时间挂起的状态,但可能会引入额外的时间成本以及潜在的竞争失败风险。 - **使用 `try_lock` 或者 `unique_lock` 配合 `defer_lock` 和 `lock()` 方法** 对于 C++ 中的标准库而言,`std::unique_lock` 支持延迟锁定的功能,允许程序员更灵活地控制何时真正执行锁定动作。这意味着可以在调用 `std::lock` 函数之前创建多个未激活的 `unique_lock` 实例,之后再一次性安全地完成全部锁定过程,从而避免部分成功的嵌套锁定模式引发死锁的可能性[^2]。 ```cpp // 使用 unique_lock 和 defer_lock 来预防死锁的例子 void safe_resource_access() { std::mutex m1, m2; // 声明两个 unique_lock 并指定 defer_lock 参数表示暂时不进行实际锁定 std::unique_lock<std::mutex> lk1(m1, std::defer_lock); std::unique_lock<std::mutex> lk2(m2, std::defer_lock); try { // 尝试以原子方式同时锁定两者 std::lock(lk1.mutex(), lk2.mutex()); // 成功后继续处理共享资源... } catch (const std::system_error& e) { // 错误处理逻辑 } } ``` - **遵循固定的加锁顺序** 当应用程序中有多个不同级别的锁存在时,始终按照相同的顺序去获取这些锁是非常重要的。比如总是先拿 A 后拿 B,绝不会反过来做。这样做能显著降低因交叉依赖造成的死锁几率。 - **利用高级同步原语** 如读写锁、信号量等更为复杂的同步工具往往提供了更好的灵活性和效率,有助于简化代码设计的同时也减少了陷入复杂竞争状况的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值