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

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

  •  2
     
  •   jeffh · 65 天前 · 6266 次点击
    这是一个创建于 65 天前的主题,其中的信息可能已经有所发展或是发生改变。
    困惑了许久的问题,google 了没找到满意的答案。
    第 1 条附言  ·  64 天前

    大家别激动,稍安勿躁。

    阻塞的问题我也了解。另外先不纠结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 条附言  ·  64 天前
    说操作系统时间片也别 bb 了,就说一句,while(true)也会切片。如果你设计一个定时任务框架,你怎么做,不要说什么挂个系统时间回调。
    第 3 条附言  ·  64 天前
    感谢 @mccreefei #39 的回复,问题已解决。

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

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

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

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

    不知道这么讲能不能明白
    watzds
        29
    watzds   64 天前 via Android
    贻笑大方
    php01
        31
    php01   64 天前
    @ipwx 科班的就是厉害,要我来描述我就只能蹦出 4 个字:时间切片了,我可说不出这么长一串来
    enenaaa
        32
    enenaaa   64 天前
    楼主三年经验看不懂这个代码不应该啊。
    axwz88
        33
    axwz88   64 天前 via Android
    楼主你这问题也太没水平了吧。。。
    onice
        34
    onice   64 天前
    以前我在项目中实现生产和消费也出现过这个问题,最大的原因就在于没有用阻塞方法。
    realpg
        35
    realpg   64 天前
    我觉得楼上的所有人对死循环的理解都有问题……
    那种能自身条件打断的不叫死循环吧……
    mxT52CRuqR6o5
        36
    mxT52CRuqR6o5   64 天前 via Android
    这不是被 try 包着,有异常就结束循环了,叫哪门子的死循环
    jeffh
        37
    jeffh   64 天前 via Android
    @php01 这我就不同意了,难道 while(true)时间就不切片了?我是科班出身,可能没大家牛 b 吧。
    jeffh
        38
    jeffh   64 天前
    @mxT52CRuqR6o5 #36 老哥,不能这么想啊,有异常就结束循环,如果人家程序就没异常呢。
    mccreefei
        39
    mccreefei   64 天前
    设定了一个 task 需要到今晚零点执行,不是会计算 delay,然后 awaitNanos(delay)。没有任务也会 await(),这里死循环怎么就 cpu100%了?
    meik2333
        40
    meik2333   64 天前
    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 资源,时间到了之后由操作系统通过信号唤醒。
    NeroKamin
        41
    NeroKamin   64 天前
    那么多 await 看不到吗
    jeffh
        42
    jeffh   64 天前
    @mccreefei 兄弟,说到点上了,理解了。
    johnniang
        43
    johnniang   64 天前 via Android
    顺便说一下,时间片是动态的,根据进程运行情况不断调整,而且操作系统会尽可能让 CPU 忙起来(尽管死循环会造成 CPU 空转)。
    nicebird
        44
    nicebird   64 天前
    阻塞了呗。
    sleep、锁、wait、poll 等操作,cpu 时间就切出去了。
    passerbytiny
        45
    passerbytiny   64 天前
    @jeffh 感情你这是只认识 sleep,不认识 await。问问题急躁不是大问题——别人会一边骂一边回答,但问完了还不认错就有问题了——后面别人直接不鸟你。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1936 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 33ms · UTC 03:09 · PVG 11:09 · LAX 19:09 · JFK 22:09
    ♥ Do have faith in what you're doing.