java--死锁,死循环会导致CPU使用率升高吗?

✅死循环会导致CPU使用率升高吗?为什么?

典型回答

死循环会导致CPU使用率升高。当代码中出现死循环时,涉及的线程会不断执行循环中的指令而不会退出,因此会持续占用处理器资源。这种情况下,CPU会花费所有可用的时间片去执行这个无尽的循环,导致几乎没有资源剩余来处理其他任务或线程。

Talk Is Cheap,Show Me The Code!!!

我们可以通过实验验证上面的结论,以下实验在8C16G的物理机上实现。内存total=15g,14g可用,因为有1g是因为Linux内核分配给SLAB了。

编写死循环代码:

js 复制代码
public class Main {

public static void main(String[] args) {

while (true){

System.out.println(System.currentTimeMillis());

//死循环输出系统时间戳,强制产生2个系统调用,可以看到CPU us 和sy 占比都会升高

}

}

}

没有跑以上代码之前的CPU使用率下图所示,us代表用户态1%,sy代表内核态0.5%。

运行代码后,CPU使用率 us和sy都有升高,同时进程列表中的java进程CPU使用一列也大幅度升高。

注意:俩个java进程,一个是IDEA编译器的,一个是通过IDEA启动的测试代码,由于死循环疯狂在IDEA控制台输出系统时间戳,导致IDEA的CPU使用率也升高了。

如果把死循环输出的那一行注释掉,可以看到只有us用户态的使用率升高了,同时IDEA的进程使用率不会升高。原因是System.out.println()和System.currentTimeMillis()都会产生系统调用进入内核态,注释掉代码后,while死循环只是用户态的程序代码,不需要进入内核态了。

✅死锁会导致CPU使用率升高吗?为什么?

典型回答

死锁不会导致升高,甚至可能降低。因为死锁发生时,涉及的线程会在等待获取锁时被挂起,而不是处于忙碌等待状态。因此,这些线程不会占用CPU资源进行计算,但它们会保持在等待状态,直到死锁被解决。

Talk Is Cheap,Show Me The Code!!!

我们可以通过实验验证上面的结论,以下实验在8C16G的物理机上实现。内存total=15g,14g可用,因为有1g是因为Linux内核分配给SLAB了。

编写死锁代码:

js 复制代码
public class Main {
    public static void main(String[] args) {
        int threadCnt = 2000; //多创建一些线程观察CPU使用率更合理
        Object[] locks = new Object[threadCnt];
        for (int i = 0; i < threadCnt; i++) { //初始化线程锁对象
            locks[i] = new Object();
        }

        for (int i = 0; i < threadCnt; i++) {
            //为了产生死锁,我们需要一个线程抢占2把锁,以下代码控制创建时相邻2个线程分别拿到相同的锁
            if (i % 2 == 0) {  //确保前一个线程拿锁顺序:锁1->锁2
                new Thread(new DeadLockTest(locks[i], locks[i + 1])).start(); 
            } else { //确保下一个线程拿锁顺序:锁2->锁1
                new Thread(new DeadLockTest(locks[i], locks[i - 1])).start(); 
            }
        }

    }

    public static class DeadLockTest implements Runnable {
        private final Object lock1;
        private final Object lock2;

        public DeadLockTest(Object lock1, Object lock2) {
            this.lock1 = lock1;
            this.lock2 = lock2;
        }

        @Override
        public void run() {
            synchronized (lock1) {
                System.out.println(Thread.currentThread().getName() + " get Lock:" + lock1); //打印线程名抢到的锁
                try {
                    Thread.sleep(1);//休眠1毫秒保证别的线程有机会拿到下面依赖的锁
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println(Thread.currentThread().getName() + " wait Lock:" + lock2);//打印线程名要拿的锁
                synchronized (lock2) {//以下会由于拿锁顺序不正确,产生死锁
                    System.out.println(Thread.currentThread().getName() + " get Lock:" + lock2);//这里由于死锁不会打印出来
                }
            }
        }
    }
}

为了验证死锁线程会不会导致CPU使用率升高,我们需要弄许多线程死锁,这样才能模拟出线上环境业务线程多,并且因为业务代码错误导致的死锁,来观察对CPU的影响。 运行前的CPU使用率

运行后的CPU使用率

从图中可以看到CPU使用率并没有明显升高,java进程占用的CPU非常低。

jstack -l

选一个Thread1查看一下线程状态:

java 复制代码
jps -l |grep -E '[0-9].Main' |awk '{print $1}' #拿到测试代码Java进程pid

jstack -l <java进程pid>|grep Thread1| awk -v FS='nid=| ' '{print $9}' |xargs printf '%d\n' #提取死锁线程Thread1的线程pid

top -Hp <java进程pid> #查看线程状态

第一列为线程的pid,可以看到状态列为S,代表线程处在sleeping状态,因为拿不到锁让出CPU的使用权。 CPU使率用是统计online-cpu的任务,即任务状态为running的任务。所以印证了死锁不会导致CPU使用率升高的结论。之所以线上出现死锁使用率降低,是因为死锁后业务代码无法继续运行,导致使用率会降低。

若有收获,就点个赞吧

相关推荐
期待のcode28 分钟前
Spring框架1—Spring的IOC核心技术1
java·后端·spring·架构
Livingbody2 小时前
10分钟完成 ERNIE-4.5-21B-A3B-Thinking深度思考模型部署
后端
胡萝卜的兔3 小时前
go 日志的分装和使用 Zap + lumberjack
开发语言·后端·golang
en-route3 小时前
如何在 Spring Boot 中指定不同的配置文件?
java·spring boot·后端
栀椩4 小时前
springboot配置请求日志
java·spring boot·后端
Swift社区5 小时前
如何解决 Spring Bean 循环依赖
java·后端·spring
爱吃烤鸡翅的酸菜鱼5 小时前
【Redis】常用数据结构之Hash篇:从常用命令到使用场景详解
数据结构·数据库·redis·后端·缓存·哈希算法
bobz9655 小时前
calico vxlan 模式如何实现和公有云一样的 VPC 功能?
后端
面汤放盐6 小时前
互联网“黑话”生存实用指南(100)
java·后端
爱吃烤鸡翅的酸菜鱼6 小时前
【Redis】常用数据结构之List篇:从常用命令到典型使用场景
数据结构·redis·后端·缓存·list