社交媒体

多线程入门

多线程入门

钩子:你的程序是条独木桥

回想第 3 篇:Java 代码从 main 方法开始,一行行往下执行。下载没下完,后面全部干等——一步卡,步步卡。

真实的软件不是这样的:微信能一边收消息一边传文件,浏览器一边加载网页一边播视频。秘密就是——它们不止一条执行流水线。

线程 = 一条独立的执行流水线。 一个进程至少有一条线程(跑 main 的那条),开多条线程,就能一心多用。

顺便颠覆一下:你现在写了几十篇的 main 方法,它自己也是个线程,名字就叫 main。

核心:两种姿势开线程

// 姿势 A:继承 Thread(简单直观,但占用了唯一的继承名额)
Thread download = new Thread() {
    @Override
    public void run() {
        System.out.println("下载中…当前线程:" + Thread.currentThread().getName());
    }
};

// 姿势 B:实现 Runnable(推荐——不占继承名额,还能配合线程池复用)
Thread ui = new Thread(() -> {
    System.out.println("渲染界面…当前线程:" + Thread.currentThread().getName());
});

关键一步:让线程跑起来,必须调 start(),不是 run():

download.start();   // ✅ 向 JVM 申请新线程,由新线程执行 run()
download.run();     // ❌ 只是普通方法调用,还在 main 线程里跑

这个坑 90% 的新手都踩过:调 run() 时一切"正常",就是没有并发效果——因为根本没有新线程,还是 main 在串行执行。

32-单线程vs多线程对比图.png

实验:亲眼看"同时"

我跑了一组真实实验(demo 里有完整代码):

串行:下载 600ms + 渲染 300ms = 922ms
并行:两个线程同时干           = 608ms(约等于最长那一段)

再让两个线程交替说话,你会看到输出顺序每次运行都可能不同——谁抢到 CPU 谁先说,这是线程调度的随机性。记住这个"随机",下一篇的大坑就藏在这里。

常用三招

方法 作用 一句话记忆
start() 真正开新线程 start 才有线程,run 只是方法
sleep(ms) 当前线程睡一会儿 让出 CPU,模拟耗时
join() 等某个线程干完再走 main 在此"堵车"等它

坑点回顾 + 下篇引线

多线程很好用,但有个致命问题没解决:多个线程改同一个变量会出事。

还记得第 8 篇的 i = i++ 吗?那只是单线程里的坑。下一篇,两个线程同时对同一个 i 做 i++,结果会让人怀疑人生——这是并发编程的第一课"线程安全",也是整个模块六的核心悬念。

速查表

要点 内容
线程是什么 一条独立的执行流水线,main 也是线程
开线程姿势 继承 Thread / 实现 Runnable(推荐)
启动 start(),不是 run()
让路 sleep(ms)
等待 join()
隐患 多线程共改一个变量 → 线程安全问题(下篇)

本文示例代码均已本地实测通过,可直接运行。
对应文件:ThreadDemo.java


橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。