使用Lock规避死锁的策略

 

在多线程编程中,死锁是一个常见且棘手的问题。死锁发生时,两个或多个线程相互等待对方释放锁,从而导致程序无法继续执行。为了提高程序的稳定性和可靠性,了解如何使用 Lock 机制规避死锁至关重要。 

1. 理解死锁

什么是死锁?

死锁是一种状态,多个线程在执行过程中,因为争夺资源而造成一种互相等待的现象。比如,线程 A 持有锁 1,等待锁 2,而线程 B 持有锁 2,等待锁 1,这样就形成了死锁。

死锁的产生条件

死锁的产生通常需要满足以下四个条件:

  1. 互斥条件:至少有一个资源是以排他模式分配的。
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:已获得的资源在未使用完之前,不能被其他进程强行剥夺。
  4. 循环等待条件:存在一种进程资源的循环等待关系。

2. 使用 Lock 规避死锁的策略

2.1 使用定时锁(tryLock)

tryLock 方法允许线程尝试获取锁,如果未能立即获取,可以选择继续执行或稍后重试。这种方式可以有效避免死锁。

示例代码

java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class DeadlockAvoidance {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    public void methodA() {
        while (true) {
            if (lock1.tryLock()) {
                try {
                    if (lock2.tryLock()) {
                        try {
                            System.out.println("方法 A: 成功获取了两个锁。");
                            break; // 成功获取锁,退出循环
                        } finally {
                            lock2.unlock();
                        }
                    }
                } finally {
                    lock1.unlock();
                }
            }
            // 如果未能获取到锁,稍作等待后重试
            try {
                Thread.sleep(50); // 或使用其他方式进行等待
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void methodB() {
        while (true) {
            if (lock2.tryLock()) {
                try {
                    if (lock1.tryLock()) {
                        try {
                            System.out.println("方法 B: 成功获取了两个锁。");
                            break; // 成功获取锁,退出循环
                        } finally {
                            lock1.unlock();
                        }
                    }
                } finally {
                    lock2.unlock();
                }
            }
            // 如果未能获取到锁,稍作等待后重试
            try {
                Thread.sleep(50); // 或使用其他方式进行等待
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

2.2 确保锁的获取顺序

确保所有线程以相同的顺序获取锁,可以有效避免死锁。通过定义一个全局的顺序来获取锁,避免不同线程以不同的顺序获取锁。

示例代码

java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class DeadlockPrevention {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    public void methodA() {
        lock1.lock();
        try {
            lock2.lock();
            try {
                System.out.println("方法 A: 成功获取了两个锁。");
            } finally {
                lock2.unlock();
            }
        } finally {
            lock1.unlock();
        }
    }

    public void methodB() {
        lock1.lock();
        try {
            lock2.lock();
            try {
                System.out.println("方法 B: 成功获取了两个锁。");
            } finally {
                lock2.unlock();
            }
        } finally {
            lock1.unlock();
        }
    }
}

2.3 使用单一锁

在某些情况下,可以通过使用单一锁来避免死锁。这种方法将所有需要同步的代码块使用同一个锁,从而避免了多个锁的竞争。

示例代码

java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class SingleLockExample {
    private final Lock lock = new ReentrantLock();

    public void methodA() {
        lock.lock();
        try {
            System.out.println("方法 A: 成功获取了锁。");
        } finally {
            lock.unlock();
        }
    }

    public void methodB() {
        lock.lock();
        try {
            System.out.println("方法 B: 成功获取了锁。");
        } finally {
            lock.unlock();
        }
    }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
死锁是操作系统中的一种并发控制问题,发生在两个或更多的进程(线程)之间,它们相互等待对方释放资源,导致所有进程都无法继续执行,形成一个僵局。每个进程都在等待其他进程所持有的资源,结果形成了一个循环依赖,这就是典型的死锁状态。 规避死锁的常见规则,也称为"死锁预防策略",主要包括以下几条: 1. **资源有序分配**:确保资源的请求按照特定顺序进行,例如,先获得低编号的资源再请求高编号的资源,这样可以避免循环等待。 2. **有限等待**:给每个进程分配一个最大等待时间,如果在一个时间间隔内无法获取所有所需的资源,就放弃并重新开始。 3. **资源预分配**:在进程开始之前尽可能多地分配资源,减少资源竞争的可能性。 4. **资源剥夺**:如果检测到死锁,进程可以主动放弃一部分已获得的资源,以便让其他进程继续执行。 5. **超时检测**:定期检查系统状态,发现可能的死锁迹象,比如资源占用情况不符合进程请求顺序,这时可以提前干预。 6. **死锁检测与恢复**:定期检查系统状态,一旦发现死锁,采取撤销进程、强制资源释放等措施解除死锁。 这些规则在设计并发系统时被广泛应用,但没有一种方法可以完全避免死锁,因为它们都需要程序员对并发行为有深入的理解和精确的控制。在实际编程中,通常结合使用这些策略和其他高级同步机制来降低死锁的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值