栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

多线程基础篇-09

Java 更新时间:发布时间: 百科书网 趣学号
文章目录

`
第九章 程序死锁


文章目录
  • 文章目录
  • 一、程序死锁
  • 二、程序死锁举例
  • 三、死锁诊断


一、程序死锁

1、交叉锁可导致程序出现死锁
线程A持有R1的锁等待获取R2的锁,线程B持有R2的锁等待获取R1的锁,这种情况最容易导致死锁问题。
2、内存不足
当并发请求系统可用内存时,如果此时系统内存不足,则可能会出现死锁的情况。举个例子,两个线程T1和T2,执行某个任务,其中T1已经获取了10MB内存,T2获取了20MB内存,如果每个线程的执行单元都需要30MB的内存,但是剩余可用的内存刚好是20MB,那么两个线程有可能都在等待彼此能够释放内存资源。
3、一问一答式的数据交换
服务端开启某个端口,等待客户端访问,客户端发送请求立即等待接收,由于某种原因服务端错过了客户端的请求,仍然在等待一问一答式的数据交换,此时服务端和客户端都在等待着双方发送数据。
4、数据库锁
无论是数据库表级别的锁,还是行级别的锁,比如某个线程执行for update语句退出了事务,其他线程访问该数据库时都将陷入死锁。
5、死循环引起的死锁
程序由于代码原因或者对某些异常处理不得当,进入死循环,虽然查看线程堆栈信息不会发现任何死锁迹象,但是程序不工作,cpu占有率又居高不下,这种死锁一般称为系统假死,是一种最为致命也是最难排查的死锁现象,由于重现困难,进程对系统资源的使用量又达到了极限,想要做出dump有时候也是非常困难的。

二、程序死锁举例

我们将举例说明程序由于交叉锁引起的死锁现象,交叉锁不仅是指自己写的代码出现了交叉的情况,如果使用某个框架或者开源库,由于对源码API的不熟悉,很有可能也会引起死锁。示例代码如下:
public class DeadLockTest {
public static void main(String[] args) {
DeadLock deadLock = new DeadLock();
OtherService otherService = new OtherService();
deadLock.setOtherService(otherService);
otherService.setDeadLock(deadLock);

    new Thread(() -> {
        while (true) {
            deadLock.m1();
        }
    }, "T1").start();
    new Thread(() -> {
        while (true) {
            otherService.s2();
        }
    }, "T2").start();
}

}
public class DeadLock {
private OtherService otherService;

public void setOtherService(OtherService otherService) {
    this.otherService = otherService;
}

// DeadLock的实例的锁-资源A
private final Object LOCK = new Object();

public void m1() {
    synchronized (LOCK) {
        System.out.println("********m1********");
        otherService.s1();
    }
}

public void m2() {
    synchronized (LOCK) {
        System.out.println("********m2********");
    }
}

}

public class OtherService {
private DeadLock deadLock;

public void setDeadLock(DeadLock deadLock) {
    this.deadLock = deadLock;
}

// OtherService的实例的锁-资源B
private final Object LOCK = new Object();

public void s1() {
    synchronized (LOCK) {
        System.out.println("========s1========");
    }
}

public void s2() {
    synchronized (LOCK) {
        System.out.println("========s2========");
        deadLock.m2();
    }
}

}
上面的程序可以看出程序有死锁的风险。

三、死锁诊断

大致知道了引起死锁的几种原因之后,本节,我们将借助诊断工具对其进行诊断。
1、交叉锁引起的死锁
运行DeadLockTest 代码,程序将陷入死锁,打开jstack工具或者jconsole工具,Jstack-l PID会直接发现死锁的信息
这里不贴出。
一般交叉锁引起的死锁线程都会进入BLOCKED状态,cpu资源占用不高,很容易借助工具来发现。
2、死循环引起的死锁(假死)
使用jstack,jconsole、jvisualvm工具或者jprofile工具进行诊断,但是不会给出明显的提示,因为工作的线程并未BLOCKED,而是始终处于RUNNABLE状态,cpu使用率高居不下,甚至不能够正常运行你的命令。
严格意义上来说死循环会导致程序假死,算不上真正的死锁,但是某个仙鹤草呢个对cpu消耗过多,导致其他线程等待cpu,内存等资源也会陷入死锁等待。

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/888730.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号