Java - 编写Java程序时,如何在Java中创建死锁并修复它?

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击人工智能教程

问题总是以“什么是死锁?”开始

当两个或多个线程在等待彼此释放所需的资源(锁定)并陷入无限等待即是死锁。它仅在多任务或多线程的情况下发生。

如何检测Java中的死锁

虽然这可以有很多答案,但我的版本是首先我会看看代码,如果我看到一个嵌套的同步块,或从一个同步的方法调用其他同步方法,或试图在不同的对象上获取锁,如果开发人员不是非常小心,就很容易造成死锁。

另一种方法是在运行应用程序实际锁定时找到它,尝试采取线程转储,在Linux中,你可以通过kill -3命令执行此操作,这将打印应用程序日志文件中所有线程的状态,并且你可以看到哪个线程被锁定在哪个线程对象上。

你可以使用fastthread.io网站等工具分析该线程转储,这些工具允许你上载线程转储并对其进行分析。

另一种方法是使用jConsole或VisualVM,它将显示哪些线程被锁定以及哪些对象被锁定。

如果你有兴趣了解故障排除工具和分析线程转储的过程,建议你看看Uriah Levy在多元视觉(PluraIsight)上的《分析Java线程转储》课程。此课程旨在详细了解Java线程转储,并熟悉其他流行的高级故障排除工具。

编写一个将导致死锁的Java程序

这是我的版本之一

package chimomo.learning.java.code.multithreading.deadlock;

/**
 * 通过强制循环等待来创建死锁
 *
 * @author Created by Chimomo
 */
public class DeadLockDemo {
    public void method1() {
        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
    }

    public void method2() {
        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
    }
}

如果method1()和method2()都由两个或多个线程调用,则存在死锁的可能性,因为如果线程1在执行method1()时在String对象上获取锁,线程2在执行method2()时在Integer对象上获取锁,等待彼此释放Integer和String上的锁以继续进行下一步,但这永远不会发生。

其理念是,你应该知道使用常见并发模式的正确方法,如果你不熟悉这些模式,那么Jose Paumard的《应用于并发和多线程的常见Java模式》是学习的好起点。

如何避免Java中的死锁

在我看来,这是最重要的部分之一:如何修复代码中的死锁?或如何避免Java中的死锁?

如果你仔细查看了上面的代码,那么你可能已经发现死锁的真正原因不是多个线程,而是它们请求锁的方式。如果你提供有序访问,则问题将得到解决。

下面是我的修复版本,它通过避免循环等待,而避免死锁,从而不需要抢占,这是需要死锁的四个条件之一。

package chimomo.learning.java.code.multithreading.deadlock;

/**
 * @author Created by Chimomo
 */
public class FixedDeadLockDemo {
    public void method1() {
        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
    }

    public void method2() {
        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
    }
}

现在没有任何死锁,因为两种方法都按相同的顺序访问Integer和String类上的锁。因此,如果线程A在Integer对象上获取锁,则线程B不会继续,直到线程A释放Integer锁。即使线程B持有String锁,线程A也不会被阻止,因为现在线程B不会期望线程A释放Integer锁以继续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值