首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Coding
V2EX  ›  程序员

不明白, JDK 源码中大量的死循环为什么没导致 CPU 100%,而我写一个 while(true)一下子就 CPU 跑满了。

  •  2
     
  •   jeffh · 20 天前 · 6009 次点击
    困惑了许久的问题,google 了没找到满意的答案。
    第 1 条附言  ·  20 天前

    大家别激动,稍安勿躁。

    阻塞的问题我也了解。另外先不纠结CPU多核的问题,while(true)长时间占满一个核我也是不同意的。while(true) sleep(1)我也了解,这里不说。

    我的疑问是JDK中的延时线程池ScheduledThreadPoolExecutor,假设现在我设定了一个task需要到今晚零点执行,那底层是否应该就死循环,来判断当前时间是否是零点。

    JDK中ScheduledThreadPoolExecutor源码如下,有for(;;)死循环:

    public RunnableScheduledFuture<?> take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                RunnableScheduledFuture<?> first = queue[0];
                if (first == null)
                    available.await();
                else {
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        return finishPoll(first);
                    first = null; // don't retain ref while waiting
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay);
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && queue[0] != null)
                available.signal();
            lock.unlock();
        }
    }
    
    第 2 条附言  ·  20 天前
    说操作系统时间片也别 bb 了,就说一句,while(true)也会切片。如果你设计一个定时任务框架,你怎么做,不要说什么挂个系统时间回调。
    第 3 条附言  ·  20 天前
    感谢 @mccreefei #39 的回复,问题已解决。

    延时线程会计算目标时间到当前时间的毫秒数 delay,然后使用 awaitNanos(delay)挂起线程,明白了。此贴终结。
    45 回复  |  直到 2019-11-22 18:12:37 +08:00
        1
    ZSeptember   20 天前
    代码呢。
        2
    W1angMh   20 天前
    代码贴出来啊兄弟
        3
    Adlered   20 天前
    没代码说毛呢
        4
    luckyrayyy   20 天前
    jdk 源码大量的死循环???
        5
    ivechan   20 天前
    2333,你该不会说得是类似下面这种死循环嘛?

    while(true) {
    recv();
    }
        6
    daozhihun   20 天前
    你确定 jdk 的死循环的线程不是在阻塞状态吗
        7
    cxtrinityy   20 天前 via Android
    先问是不是
        8
    LuckyBoyGirl   20 天前
    你这个问题就类似 为何消费者也是用的 while(true) cpu 缺没有跑满 哈哈
        9
    wutiantong   20 天前
    这种问题自己留着琢磨多好。
        10
    lhx2008   20 天前 via Android
    JDK 里面的死循环一般里面都带阻塞的
        11
    tabris17   20 天前
    while(true) sleep(1)

    你给我跑满 cpu 试试
        12
    guolaopi   20 天前
    1.跟 debug 有关
    2.人家的死循环是迫不得已的为了实现某种机制吧,比如 socket,代码中肯定包含终止循环的方法
    3.不贴代码让人怎么猜
        13
    henices   20 天前
    现在的 CPU 多是多核,一般情况只能将某个核给跑满,对整个系统影响其实不大。
        14
    ExploreWay   20 天前
    轮询超时机制限制,一般都会有吧!
        15
    zivyou   20 天前
    循环体中有让线程挂起的地方
        16
    ffkjjj   20 天前
    首先, JDK 里面一般都是阻塞的
    其次, 你试一下以下代码 cpu 占用的区别
    while(true){
    }

    while(true){
    try {
    Thread.sleep(100L);
    } catch (InterruptedException e) {
    return;
    }
    }
        17
    sheep3   20 天前
    死循环一直算肯定跑满,你说的肯定有阻塞
        18
    dosmlp   20 天前   ♥ 2
    说告诉你死循环=cpu 占用 100%的!!!??
        19
    XiLemon   20 天前 via iPhone
    说的是不是 cas 操作相关的代码
        20
    jeffh   20 天前
    @XiLemon #19 cas 还好,比较虽然死循环但是总有成功的一次,不会长期占用 cpu 资源
        21
    exip   20 天前 via Android
    人家那是有退出条件的死循环,你这是无条件的死循环.
        22
    JingW   20 天前
    你 await 一下你也不占 CPU
        23
    XiLemon   20 天前
    @jeffh #20 你这个代码贴的,里面不是有阻塞的方法么。。。
        24
    ipwx   20 天前 via Android
    这种典型就是操作系统原理没学过才会发出的疑问。科班还是有科班的底蕴的。
        25
    ipwx   20 天前 via Android   ♥ 3
    这么说吧,线程占用 cpu 必须是在运行,而线程被操作系统调度才会被运行。因为 io 或者其他原因阻塞,线程会进入操作系统的等待队列,不会被运行。线程即使不进入阻塞,也不一定一直运行,操作系统随时可以打断线程,让它暂停,让渡资源给别的线程运行一段时间,再切换回来。当然资源充足情况下操作系统一般不会主动打断线程运行。
        26
    opengps   20 天前 via Android   ♥ 3
    死循环不可怕,可怕的是死循环内部不休息
        27
    misaka19000   20 天前
    楼主基础堪忧
        28
    Raymon111111   20 天前
    死循环但并不占用 cpu

    不知道这么讲能不能明白
        29
    watzds   20 天前 via Android
    贻笑大方
        31
    php01   20 天前
    @ipwx 科班的就是厉害,要我来描述我就只能蹦出 4 个字:时间切片了,我可说不出这么长一串来
        32
    enenaaa   20 天前
    楼主三年经验看不懂这个代码不应该啊。
        33
    axwz88   20 天前 via Android
    楼主你这问题也太没水平了吧。。。
        34
    onice   20 天前
    以前我在项目中实现生产和消费也出现过这个问题,最大的原因就在于没有用阻塞方法。
        35
    realpg   20 天前
    我觉得楼上的所有人对死循环的理解都有问题……
    那种能自身条件打断的不叫死循环吧……
        36
    mxT52CRuqR6o5   20 天前 via Android
    这不是被 try 包着,有异常就结束循环了,叫哪门子的死循环
        37
    jeffh   20 天前 via Android
    @php01 这我就不同意了,难道 while(true)时间就不切片了?我是科班出身,可能没大家牛 b 吧。
        38
    jeffh   20 天前
    @mxT52CRuqR6o5 #36 老哥,不能这么想啊,有异常就结束循环,如果人家程序就没异常呢。
        39
    mccreefei   20 天前
    设定了一个 task 需要到今晚零点执行,不是会计算 delay,然后 awaitNanos(delay)。没有任务也会 await(),这里死循环怎么就 cpu100%了?
        40
    meik2333   20 天前
    https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html#awaitNanos-long-

    我不会 Java,使用 `RunnableScheduledFuture await` 关键词从 Google 搜到了上面的链接。

    简单的猜测一下,你给出的代码和 `while(true) sleep(1)` 没有本质的区别,sleep 之后线程挂起,不再占用 CPU 资源,时间到了之后由操作系统通过信号唤醒。
        41
    NeroKamin   20 天前
    那么多 await 看不到吗
        42
    jeffh   20 天前
    @mccreefei 兄弟,说到点上了,理解了。
        43
    johnniang   20 天前 via Android
    顺便说一下,时间片是动态的,根据进程运行情况不断调整,而且操作系统会尽可能让 CPU 忙起来(尽管死循环会造成 CPU 空转)。
        44
    nicebird   20 天前
    阻塞了呗。
    sleep、锁、wait、poll 等操作,cpu 时间就切出去了。
        45
    passerbytiny   20 天前
    @jeffh 感情你这是只认识 sleep,不认识 await。问问题急躁不是大问题——别人会一边骂一边回答,但问完了还不认错就有问题了——后面别人直接不鸟你。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2201 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 30ms · UTC 15:51 · PVG 23:51 · LAX 07:51 · JFK 10:51
    ♥ Do have faith in what you're doing.