【048】线程饿到罢工?5 招教你喂饱并发线程


在这里插入图片描述

📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌

📙 作者: 编程技术圈(哇哥面试陪跑)
👉 欢迎关注、分享、评论
✔️ 持续分享更多干货内容
🌐🌏🌎➕tcmeta, 欢迎沟通交流

📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌📌

零、引入

王二的脸比过期的馒头还白,手指在键盘上戳了半天,屏幕上的日志却像冻住的流水 —— 三个 “统计线程” 窝在角落不动弹,堆积的订单数据快把数据库表撑得冒尖。“明明给了线程优先级,咋高优先级的‘处理线程’占着 CPU 不撒手,低优先级的统计线程连口汤都喝不上?” 他扯着嗓子喊,惊得隔壁哇哥手里的搪瓷缸子晃出半杯茶。

哇哥呷了口茶,茶叶梗在水面上打转,慢悠悠道:“这不是线程偷懒,是你把它们饿坏了 —— 就像食堂里让壮汉抢完所有馒头,瘦小子只能饿着肚子蹲墙角,时间长了谁还愿意给你干活?”

点赞 + 关注,跟着哇哥把线程饥饿的病根挖透,5 招就能让每个线程都有 “饭吃”,下次再写并发代码,保准不会再出这种 “饿肚子” 的乱子。

在这里插入图片描述

一、王二的 “饿肚子” 代码:高优先级线程的 “霸权主义”

在这里插入图片描述
王二写的是电商订单系统,用三个线程处理订单,两个线程统计销量 —— 他觉得 “处理订单” 更重要,就把处理线程的优先级设成最高,统计线程设成最低。代码看着没毛病,跑起来却出了幺蛾子:

package cn.tcmeta.juc;


import java.util.concurrent.TimeUnit;

/**
 * @author: laoren
 * @date: 2025/12/18 12:26
 * @description: 王二的坑:线程优先级设太偏,低优先级线程饿肚子
 * @version: 1.0.0
 */
public class ThreadStarvationSample {

    // 订单计数器(原子类保证线程安全)
    private static int orderCount = 0;
    // 销量统计器
    private static int salesCount = 0;

    static void main() {
        // 1. 高优先级:订单处理线程(3个)
        for (int i = 0; i < 3; i++) {
            Thread processThread = new Thread(() -> {
                while (true) {
                    // 模拟处理订单:每次+1,耗时10ms
                    orderCount++;
                    try {
                        TimeUnit.MILLISECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                    // 每处理100单打印一次
                    if (orderCount % 100 == 0) {
                        System.out.println(Thread.currentThread().getName() + ":处理订单" + orderCount + "单");
                    }
                }
            }, "Process-Thread-" + i);
            // 设为最高优先级(10)
            processThread.setPriority(Thread.MAX_PRIORITY);
            processThread.start();
        }

        // 2. 低优先级:销量统计线程(2个)
        for (int i = 0; i < 2; i++) {
            Thread statThread = getThread(i);
            statThread.start();
        }
    }

    private static Thread getThread(int i) {
        Thread statThread = new Thread(() -> {
            while (true) {
                // 模拟统计销量:每次+1,耗时5ms
                salesCount++;
                try {
                    TimeUnit.MILLISECONDS.sleep(5);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
                // 每统计50次打印一次(理论上比处理线程打印更频繁)
                if (salesCount % 50 == 0) {
                    System.out.println("【统计线程】:统计销量" + salesCount + "次");
                }
            }
        }, "Stat-Thread-" + i);
        // 设为最低优先级(1)
        statThread.setPriority(Thread.MIN_PRIORITY);
        return statThread;
    }
}

在这里插入图片描述

【注意事项】: 如果cpu资源充足,则测试结果可能会不是特别明显.

王二盯着日志发呆:“统计线程明明耗时更短,咋干活这么慢?”

哇哥用手指敲了敲屏幕:“这就是线程饥饿 —— 低优先级线程长期抢不到 CPU 时间片,就像食堂里被壮汉挤到一边的学生,连餐盘都递不出去。Java 的线程优先级是‘提示’操作系统,不是‘命令’,但你把差距拉到 10 比 1,操作系统就偏着高优先级的来,低优先级的只能捡漏。”

他顿了顿,又道:“更糟的是,你这处理线程是死循环,一旦占了 CPU,就像霸着餐桌不挪窝,统计线程只能饿着。”

二、用 “食堂打饭” 讲透线程饥饿:不是不干活,是没机会干活

在这里插入图片描述

哇哥拽过王二桌上的草稿纸,画了个歪歪扭扭的食堂窗口,旁边标着 “CPU 时间片”,三个壮汉堵在窗口,两个瘦小子蹲在墙角 —— 这是他的拿手好戏,再玄乎的技术,到他手里都能变成街头巷尾的事儿。

“线程饥饿,说白了就是‘有活干,没资源’,” 哇哥指着草稿纸,“就像这食堂,窗口(CPU)就一个,壮汉(高优先级线程)一直抢着打饭,瘦小子(低优先级线程)连窗口都挨不着,不是不想打饭,是没机会。”

他擦掉草稿纸,又画了三个场景:

  • 优先级倒置:壮汉插队,瘦小子永远排最后;
  • 锁霸占:有人打了饭不离开窗口,抱着碗在那吃,后面的人只能等;
  • 永久阻塞:瘦小子被人堵在食堂门外,根本进不来。

“这就是线程饥饿的三大病根,” 哇哥总结,“王二你犯的是第一类 —— 优先级设得太极端;还有人用 synchronized 锁的时候,在锁里写个死循环,那就是第二类‘锁霸占’;用 Thread.join () 不设超时时间,就是第三类‘永久阻塞’。”

👉 线程饥饿核心定义(王二记在烟盒内侧)

王二掏出皱巴巴的烟盒,用铅笔歪歪扭扭地写:

线程饥饿:线程因长期无法获取所需资源(CPU 时间片、锁、IO 等),导致任务无法推进的现象。它不是线程死锁(互相等),也不是线程阻塞(暂时等),而是 “永久或长期没机会”—— 就像饿肚子的人,不是不想吃饭,是根本没饭吃。

在这里插入图片描述

三、5 招根治线程饥饿:从 “霸餐” 到 “分餐” 的蜕变

在这里插入图片描述
哇哥拿过王二的鼠标,说:“要让线程不饿肚子,就得打破‘霸权主义’,搞‘分餐制’。这 5 招下去,保证每个线程都有饭吃。”

➡️ 第 1 招:抛弃 “极端优先级”,改用 “平等调度”

Java 的线程优先级(1-10)只是给操作系统的 “建议”,不是 “命令”,极端优先级只会加剧饥饿。解决方法是**:不用手动设优先级,让线程平等竞争 —— 就像食堂里大家排队,不分壮汉瘦小子。**

  • 优化代码 1:移除优先级设置
package cn.tcmeta.juc;


import java.util.concurrent.TimeUnit;

/**
 * @author: laoren
 * @date: 2025/12/18 13:18
 * @description: 优化点:删除所有setPriority代码,线程默认优先级5
 * @version: 1.0.0
 */
public class ThreadStarvationFix1 {
    private static int orderCount = 0;
    private static int salesCount = 0;

    static void main() {
        // 订单处理线程:不设优先级
        for (int i = 0; i < 3; i++) {
            Thread processThread = new Thread(() -> {
                while (true) {
                    orderCount++;
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                    if (orderCount % 100 == 0) {
                        System.out.println(Thread.currentThread().getName() + ":处理订单" + orderCount + "单");
                    }
                }
            }, "Process-Thread-" + i);
            // 移除setPriority
            processThread.start();
        }

        // 销量统计线程:不设优先级
        for (int i = 0; i < 2; i++) {
            Thread statThread = new Thread(() -> {
                while (true) {
                    salesCount++;
                    try {
                        TimeUnit.MILLISECONDS.sleep(5);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                    if (salesCount % 50 == 0) {
                        System.out.println("【统计线程】:统计销量" + salesCount + "次");
                    }
                }
            }, "Stat-Thread-" + i);
            // 移除setPriority
            statThread.start();
        }
    }
}

运行结果:统计线程 “吃饱饭” 了
在这里插入图片描述
王二眼睛亮了:“统计线程终于正常了!原来优先级是个坑。”

“不是优先级是坑,是你把它用成了坑,” 哇哥说,“除非有明确的实时需求(比如嵌入式开发),否则别手动改优先级 ——Java 线程调度本来就公平,你瞎插手反而乱套。”

📢 第 2 招:用 “公平锁” 代替 “非公平锁”,拒绝 “锁插队”

synchronized 和 ReentrantLock 默认都是 “非公平锁”—— 线程释放锁时,等待队列里的线程和新线程会 “抢锁”,新线程容易插队,导致等待队列里的线程饿肚子。解决方法是用 ReentrantLock 的 “公平锁”,让线程排队,谁等得久谁先拿锁。

  • 反例:非公平锁导致的饥饿
package cn.tcmeta.juc;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: laoren
 * @date: 2025/12/18 13:20
 * @description: 非公平锁:新线程插队,等待线程饥饿
 * @version: 1.0.0
 */
public class UnfairLockStarvation {
    // 默认非公平锁
    private static final Lock UNFAIR_LOCK = new ReentrantLock();
    private static int count = 0;
    static void main() {
        // 1. 先启动一个“长占锁”线程
        Thread longLockThread = new Thread(() -> {
            while (true) {
                UNFAIR_LOCK.lock();
                try {
                    count++;
                    // 占锁100ms,模拟长耗时操作
                    TimeUnit.MILLISECONDS.sleep(100);
                    if (count % 10 == 0) {
                        System.out.println("长占锁线程:count=" + count);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                } finally {
                    UNFAIR_LOCK.unlock();
                }
            }
        }, "Long-Lock-Thread");
        longLockThread.start();

        // 2. 启动5个“等待锁”线程
        for (int i = 0; i < 5; i++) {
            Thread waitThread = new Thread(() -> {
                while (true) {
                    UNFAIR_LOCK.lock();
                    try {
                        count++;
                        System.out.println(Thread.currentThread().getName() + ":抢到锁,count=" + count);
                    } finally {
                        UNFAIR_LOCK.unlock();
                    }
                    try {
                        // 抢完锁歇50ms,给别人机会(但非公平锁还是会被插队)
                        TimeUnit.MILLISECONDS.sleep(50);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }, "Wait-Thread-" + i);
            waitThread.start();
        }
    }
}

运行结果:等待线程抢不到锁(饥饿)
在这里插入图片描述

优化代码 2:改用公平锁

package cn.tcmeta.juc;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: laoren
 * @date: 2025/12/18 13:23
 * @description: 优化点:ReentrantLock(true)启用公平锁
 * @version: 1.0.0
 */
public class FairLockFix {

    // 公平锁:按等待顺序分配锁
    private static final Lock FAIR_LOCK = new ReentrantLock(true);
    private static int count = 0;

    static void main() {
        // 长占锁线程(逻辑不变)
        Thread longLockThread = new Thread(() -> {
            while (true) {
                FAIR_LOCK.lock();
                try {
                    count++;
                    TimeUnit.MILLISECONDS.sleep(100);
                    if (count % 10 == 0) {
                        System.out.println("长占锁线程:count=" + count);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                } finally {
                    FAIR_LOCK.unlock();
                }
            }
        }, "Long-Lock-Thread");
        longLockThread.start();

        // 等待锁线程(逻辑不变)
        for (int i = 0; i < 5; i++) {
            Thread waitThread = new Thread(() -> {
                while (true) {
                    FAIR_LOCK.lock();
                    try {
                        count++;
                        System.out.println(Thread.currentThread().getName() + ":抢到锁,count=" + count);
                    } finally {
                        FAIR_LOCK.unlock();
                    }
                    try {
                        TimeUnit.MILLISECONDS.sleep(50);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }, "Wait-Thread-" + i);
            waitThread.start();
        }
    }
}

运行结果:等待线程按顺序抢锁

Wait-Thread-0:抢到锁,count=1
Wait-Thread-1:抢到锁,count=2
长占锁线程:count=10
Wait-Thread-2:抢到锁,count=11
Wait-Thread-3:抢到锁,count=12

哇哥解释:“公平锁就像食堂窗口贴了‘按顺序排队’的牌子,谁先来谁先打饭,不会让新到的人插队 —— 虽然效率比非公平锁略低,但能保证每个线程都有机会。”

✔️ 第 3 招:避免 “锁霸占”,拆分长耗时操作

线程持有锁时做长耗时操作(比如 IO、循环计算),会让其他线程长期等不到锁,导致饥饿。解决方法是:把长耗时操作移出锁外,让锁 “快拿快放”—— 就像打饭时,先把碗递过去打饭,拿到饭后找地方吃,别堵在窗口。

反例:锁内做长耗时操作

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// 锁内做长耗时操作,导致其他线程饥饿
public class LongTaskInLock {
    private static final Lock LOCK = new ReentrantLock();
    private static String data = "";

    public static void main(String[] args) {
        // 长任务线程:锁内做IO操作(耗时)
        Thread longTaskThread = new Thread(() -> {
            while (true) {
                LOCK.lock();
                try {
                    System.out.println("长任务线程:开始获取数据(锁内)");
                    // 模拟网络IO(长耗时),本应移出锁外
                    TimeUnit.SECONDS.sleep(3);
                    data = "新数据-" + System.currentTimeMillis();
                    System.out.println("长任务线程:数据获取完成");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                } finally {
                    LOCK.unlock();
                }
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }, "Long-Task-Thread");
        longTaskThread.start();

        // 短任务线程:抢锁查数据,却一直等
        Thread shortTaskThread = new Thread(() -> {
            while (true) {
                LOCK.lock();
                try {
                    System.out.println("短任务线程:查到数据=" + data);
                } finally {
                    LOCK.unlock();
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }, "Short-Task-Thread");
        shortTaskThread.start();
    }
}

优化代码 :长耗时操作移出锁外

// 优化点:锁内只做核心操作,长耗时操作移到锁外
public class SplitLongTaskFix {
    private static final Lock LOCK = new ReentrantLock();
    private static String data = "";

    public static void main(String[] args) {
        Thread longTaskThread = new Thread(() -> {
            while (true) {
                String tempData = "";
                // 1. 长耗时操作:移出锁外(无锁)
                System.out.println("长任务线程:开始获取数据(无锁)");
                try {
                    TimeUnit.SECONDS.sleep(3);
                    tempData = "新数据-" + System.currentTimeMillis();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }

                // 2. 核心操作:锁内只做赋值(快拿快放)
                LOCK.lock();
                try {
                    data = tempData;
                    System.out.println("长任务线程:数据更新完成");
                } finally {
                    LOCK.unlock();
                }

                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }, "Long-Task-Thread");
        longTaskThread.start();

        // 短任务线程(逻辑不变)
        Thread shortTaskThread = new Thread(() -> {
            while (true) {
                LOCK.lock();
                try {
                    System.out.println("短任务线程:查到数据=" + data);
                } finally {
                    LOCK.unlock();
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }, "Short-Task-Thread");
        shortTaskThread.start();
    }
}

运行结果:短任务线程不再饥饿

长任务线程:开始获取数据(无锁)
短任务线程:查到数据=
短任务线程:查到数据=
短任务线程:查到数据=
长任务线程:数据更新完成
短任务线程:查到数据=新数据-1678901234567

❓ 第 4 招:用 “线程池” 管理线程,避免 “无节制创建”

王二之前手动创建线程,导致线程太多,CPU 调度不过来,低优先级线程饥饿。解决方法是用线程池 —— 线程池会复用线程,控制并发数,让每个线程都有公平的调度机会,就像食堂里的 “取号机”,不会让太多人挤在窗口。

线程池替代手动创建线程

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

// 用线程池管理线程,避免饥饿
public class ThreadPoolFix {
    private static int orderCount = 0;
    private static int salesCount = 0;

    public static void main(String[] args) {
        // 1. 创建线程池:核心线程5个,足够处理任务
        ExecutorService threadPool = Executors.newFixedThreadPool(5);

        // 2. 提交3个订单处理任务
        for (int i = 0; i < 3; i++) {
            threadPool.submit(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    orderCount++;
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                    if (orderCount % 100 == 0) {
                        System.out.println(Thread.currentThread().getName() + ":处理订单" + orderCount + "单");
                    }
                }
            });
        }

        // 3. 提交2个销量统计任务
        for (int i = 0; i < 2; i++) {
            threadPool.submit(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    salesCount++;
                    try {
                        TimeUnit.MILLISECONDS.sleep(5);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                    if (salesCount % 50 == 0) {
                        System.out.println("【统计线程】:统计销量" + salesCount + "次");
                    }
                }
            });
        }

        // 4. 优雅关闭(实际生产环境需处理)
        Runtime.getRuntime().addShutdownHook(new Thread(threadPool::shutdownNow));
    }
}

哇哥补充:“线程池的核心是‘复用’和‘控制’—— 不会像手动创建线程那样,100 个线程抢 CPU,导致部分线程饿死;而且线程池的调度是公平的,每个任务都有机会被执行。”

🔔 第 5 招:给阻塞操作加 “超时时间”,拒绝 “永久等待”

用Thread.join()、Object.wait()、BlockingQueue.take()等方法时,如果不设超时时间,线程会永久阻塞,导致饥饿。解决方法是用带超时的重载方法,比如join(1000)、wait(1000),让线程 “等不及就走”,不会一直耗着。

阻塞操作加超时

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

// 阻塞操作加超时,避免永久等待
public class TimeoutFix {
    private static final BlockingQueue<String> QUEUE = new ArrayBlockingQueue<>(5);

    public static void main(String[] args) {
        // 生产者线程:10秒后才放数据
        Thread producer = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(10);
                QUEUE.put("订单数据");
                System.out.println("生产者:放入订单数据");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }, "Producer-Thread");
        producer.start();

        // 消费者线程:带超时获取数据(不会永久等待)
        Thread consumer = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 带超时获取:3秒没数据就超时
                    String data = QUEUE.poll(3, TimeUnit.SECONDS);
                    if (data != null) {
                        System.out.println("消费者:拿到数据=" + data);
                    } else {
                        System.out.println("消费者:等待超时,先干别的活");
                        // 超时后做其他任务,避免饥饿
                        doOtherWork();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }, "Consumer-Thread");
        consumer.start();
    }

    // 超时后执行的其他任务
    private static void doOtherWork() {
        System.out.println("消费者:执行其他任务(比如清理缓存)");
    }
}

运行结果:消费者不会永久等待

消费者:等待超时,先干别的活
消费者:执行其他任务(比如清理缓存)
消费者:等待超时,先干别的活
消费者:执行其他任务(比如清理缓存)
生产者:放入订单数据
消费者:拿到数据=订单数据

四、面试必问:线程饥饿核心题(附答案)

哇哥知道王二要面试,特意整理了 3 道高频题,让他抄在小本本上,像考前划重点:
在这里插入图片描述

💯 面试题 1:什么是线程饥饿?它和死锁、阻塞有什么区别?

用 “食堂场景” 答,面试官一听就懂:

  • 线程饥饿:线程长期拿不到资源(CPU、锁),没机会执行 —— 就像学生一直被插队,没饭吃;
  • 死锁:线程互相等待对方的资源,谁都动不了 —— 就像两个学生互相抢对方的餐盘,都吃不上饭;
  • 阻塞:线程暂时等待资源(比如 wait、sleep),资源到位后会继续执行 —— 就像学生排队打饭,暂时没轮到,但迟早能吃上。

核心区别:饥饿是 “长期没机会”,死锁是 “互相等”,阻塞是 “暂时等”。

✔️ 面试题 2:导致线程饥饿的常见原因有哪些?

三大病根,对应三大场景:

  • 优先级倒置:低优先级线程抢不过高优先级线程,长期得不到 CPU 时间片;
  • 锁资源霸占:线程持有锁后做长耗时操作,或死循环不释放锁,其他线程长期等不到锁;
  • 永久阻塞:线程调用无超时的阻塞方法(join ()、wait ()、take ()),永久等待资源。

🔥 面试题 3:如何防止线程饥饿?(必答,分点说)

记住 “5 招根治法”,结合场景答:

  • 平等调度:不手动设置极端线程优先级,让线程公平竞争;
  • 公平锁机制:用 ReentrantLock (true) 实现公平锁,按等待顺序分配锁,避免插队;
  • 锁快拿快放:把长耗时操作移出锁外,只在锁内做核心操作(如赋值、修改);
  • 线程池管理:用线程池复用线程、控制并发数,避免无节制创建线程导致调度失衡;
  • 阻塞加超时:阻塞操作(join、wait、poll)用带超时的重载方法,避免永久等待。

五、总结:线程饥饿根治心法(王二编的顺口溜)

王二把 5 招编成顺口溜,贴在键盘上,生怕再忘:

  • 优先级别乱设,平等调度才和谐;
  • 公平锁来排队,谁先等的谁先会;
  • 锁内任务要简短,快拿快放别偷懒;
  • 线程池来管线程,调度公平不添乱;
  • 阻塞操作加超时,别让线程空等待。

哇哥看着王二把优化后的代码部署上线,日志里统计线程和处理线程各司其职,终于点了点头,说出那句收尾的话:

哇哥说:“线程如人,饿极了便不会再为你出力;所谓并发,从来不是让强者通吃,而是让每个线程都有碗饭吃 —— 这才是写代码的良心,也是搞并发的根本。你若只盯着‘高效’,忘了‘公平’,代码早晚会给你颜色看。”

关注我,下次咱们扒一扒 “线程调度的底层原理”—— 从 Java 线程到操作系统内核,带你看透 CPU 是如何给线程 “分饭” 的,让你从根上理解并发问题!

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值