如何构建一个死锁?

程序中的死锁指的是两个或两个以上的线程,相互等待对方释放某个锁,而造成无限等待的一种情况

如何构建死锁?

以下就是一个死锁的例子

package MultiThread;

/** 
 * Java program to create a deadlock by imposing circular wait.
 * 
 * @author William
 * 
 */

public class DeadLock {


    private class Running1 implements Runnable {
        /*
         * This method request two locks, first String and then Integer
         */
        @Override
        public void run() {
            while (true) {
                synchronized (String.class) {
                    System.out.println("Thread1 Aquired lock on String.class object");

                    synchronized (Integer.class) {
                        System.out.println("Thread1 Aquired lock on Integer.class object");
                    }
                }               
            }
        }

    }

    private class Running2 implements Runnable {
        /*
         * This method also requests same two lock but in exactly
         * Opposite order i.e. first Integer and then String
         * This creates potential deadlock, if one thread holds String lock
         * and other holds Integer lock and they wait for each other, forever
         */
        @Override
        public void run() {
            while (true) {
                synchronized (Integer.class) {
                    System.out.println("Thread2 Aquired lock on Integer.class object");

                    synchronized (String.class) {
                        System.out.println("Thread2 Aquired lock on String.class object");
                    }
                }               
            }
        }       
    }

    public static void main(String[] args) {
        DeadLock deadLock = new DeadLock();
        Running1 r1 = deadLock.new Running1();
        Running2 r2 = deadLock.new Running2();

        Thread thread1 = new Thread(r1);
        Thread thread2 = new Thread(r2);

        thread1.start();
        thread2.start();
    }
}
Console output :

Thread1 Aquired lock on String.class object
Thread2 Aquired lock on Integer.class object
无限等待

在上面这个例子中,我们有两个线程,以相反的顺序去获取两个锁,最后陷入了Thread1持有String锁,等待Integer锁,Thread2持有Integer锁,等待String锁的无限等待,即死锁情景

如何避免死锁?

避免死锁的关键在于应使不同线程获取锁的顺序保持一致,例如都先获取String锁,再获取Integer锁,我们可以做如下修改

package MultiThread;

/** 
 * Java program to create a deadlock by imposing circular wait.
 * 
 * @author William
 * 
 */

public class DeadLock {


    private class Running1 implements Runnable {
        /*
         * This method request two locks, first String and then Integer
         */
        @Override
        public void run() {
            while (true) {
                synchronized (String.class) {
                    System.out.println("Thread1 Aquired lock on String.class object");

                    synchronized (Integer.class) {
                        System.out.println("Thread1 Aquired lock on Integer.class object");
                    }
                }               
            }
        }

    }

    private class Running2 implements Runnable {
        /*
         * This method requests same two lock in the same
         * order i.e. first String and then Integer
         * This will not create any deadlock risk 
         */
        @Override
        public void run() {
            while (true) {
                synchronized (String.class) {
                    System.out.println("Thread2 Aquired lock on Integer.class object");

                    synchronized (Integer.class) {
                        System.out.println("Thread2 Aquired lock on String.class object");
                    }
                }               
            }
        }       
    }

    public static void main(String[] args) {
        DeadLock deadLock = new DeadLock();
        Running1 r1 = deadLock.new Running1();
        Running2 r2 = deadLock.new Running2();

        Thread thread1 = new Thread(r1);
        Thread thread2 = new Thread(r2);

        thread1.start();
        thread2.start();
    }
}
Console output :

Thread1 Aquired lock on String.class object
Thread1 Aquired lock on Integer.class object
Thread1 Aquired lock on String.class object
Thread1 Aquired lock on Integer.class object
Thread2 Aquired lock on String.class object
Thread2 Aquired lock on Integer.class object
...
### 防止线程死锁的方法和最佳实践 为了有效地避免和解决线程死锁问题,可以从以下几个方面入手: #### 1. 统一资源加锁顺序 确保所有线程按照相同的顺序获取锁是一个有效的防止单元。如果多个线程都需要获取两个或更多锁,则应保证这些线程总是按相同顺序请求这些锁[^2]。通过这种方式,可以显著降低因不同线程以不同的顺序申请同一组资源而导致的循环等待。 #### 2. 使用超时机制 当尝试获取某个锁时,可以设置一个最大等待时间。如果超过这个时间段仍未成功获得该锁,则放弃此次操作并回滚任何已做的更改。这种方法能够打破潜在的死锁局面[^4]。具体实现上可利用 `tryLock()` 方法代替传统的 `lock()` 来达到目的。 ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.TimeUnit; public class TimeoutExample { public void performOperation(Lock lockA, Lock lockB) throws InterruptedException { boolean isLockedA = false; boolean isLockedB = false; try { isLockedA = lockA.tryLock(500, TimeUnit.MILLISECONDS); isLockedB = lockB.tryLock(500, TimeUnit.MILLISECONDS); if (isLockedA && isLockedB){ // Critical section code here... } else{ throw new IllegalStateException("Could not acquire both locks"); } } finally { if(isLockedA){ lockA.unlock(); } if(isLockedB){ lockB.unlock(); } } } } ``` #### 3. 减少锁的作用范围 尽可能缩短持有锁的时间长度,即让临界区越短越好。这样不仅可以提高系统的吞吐量,还能减少发生死锁的可能性[^3]。例如,在进入同步块之前先完成一些准备工作;或者考虑将大锁拆分为更细粒度的小锁,从而允许更多的并发访问。 #### 4. 设计无环依赖结构 构建应用程序逻辑时要特别注意不要形成闭环调用关系——也就是 A 等待 B 完成的同时 B 又反过来等着 A 的情况。这种架构上的调整往往能从根本上消除死锁隐患[^1]。 #### 5. 应用高级并发工具类 现代编程语言提供了许多内置的支持来帮助开发者管理复杂的多线程环境下的资源共享问题。比如 Java 中有 ReentrantLock 提供公平性选项、ReadWriteLock 支持读写分离等等特性都可以用来优化传统互斥方式带来的性能瓶颈及风险。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值