1. 引言

在实际开发中,我们经常需要让程序“同时”做多件事。实现这一点的方式有多种,而最核心的手段之一就是多任务处理(multitasking)

✅ 多任务处理:指多个任务并发执行,各自完成不同的工作,共享内存和资源,但逻辑上并行运行。

虽然这些任务看似“同时”运行,但实际上可能是由操作系统或 JVM 调度,在单核或多核 CPU 上快速切换实现的并发效果。关键在于,我们要让程序具备处理并发的能力。

2. 原生线程(Native Threads)

Java 中实现并发的标准方式是使用线程(Thread),而 Java 所使用的正是操作系统级别的“原生线程”。

⚠️ 原生线程直接映射到操作系统的执行单元(即 OS Thread),由操作系统负责调度到 CPU 核心上运行。这意味着:

  • 线程的创建、切换、销毁都依赖 OS 支持
  • 性能高,尤其适合长时间运行的任务
  • JVM 无需自己管理线程调度底层细节

✅ 自 Java 1.2 起,JVM 全面采用原生线程模型,无论运行在 Windows、Linux 还是 macOS 上,这一机制保持一致。

也就是说,只要你用了以下任意一种标准并发工具,你就在使用原生线程:

  • java.lang.Thread
  • java.util.concurrent.Executor
  • java.util.concurrent.ExecutorService
  • ForkJoinPool
  • CompletableFuture(底层依赖线程池)

💡 小结:原生线程性能好、支持广,是目前 Java 并发的基石。但它的“昂贵”之处在于——每个线程都会占用系统资源(栈内存、内核数据结构等),频繁创建销毁会带来显著开销。

3. 绿色线程(Green Threads)

绿色线程是一种用户态线程,它不直接对应操作系统线程,而是由运行时环境(如虚拟机或框架)在少数几个原生线程上模拟出多个逻辑线程

工作原理简单来说就是:

多个绿色线程 → 映射到少量原生线程 → 由运行时系统调度执行

优势 ✅

  • 创建/销毁成本极低
  • 数量可成千上万(不像原生线程受限于系统资源)
  • 更适合短生命周期任务(比如处理大量 HTTP 请求)

劣势 ❌

  • 无法真正并行(只能在一个原生线程上轮流跑)
  • 容易因某个任务阻塞导致整体卡住
  • 需要运行时深度介入调度逻辑

⚠️ Java 曾经在早期版本(1.1 及之前)使用绿色线程作为默认模型,但从 Java 1.2 开始彻底转向原生线程,至今 JVM 层面不再支持绿色线程。

虽然 JVM 没有内置支持,但一些第三方库通过字节码增强或 Java Agent 实现了类似能力——比如我们接下来要讲的 Fibers

4. Fiber(纤程)

Fiber 是一种轻量级并发单元,概念上接近绿色线程,但关键区别在于:它是协作式(cooperative)而非抢占式(preemptive)的多任务模型

对比项 原生线程 / 绿色线程 Fiber
调度方式 抢占式(系统决定何时切换) 协作式(代码主动 yield)
切换控制 OS 或运行时强制中断 开发者显式声明可暂停点
上下文开销 高(内核态切换) 极低(用户态保存栈)
并发密度 数千级 数十万级

✅ Fiber 的核心思想是:“我运行到某个安全点时,自己说一声‘我可以让出’”,而不是被系统强行打断。

⚠️ 如果你的 fiber 代码中没有 yield 点,那它就会一直霸占线程,其他 fiber 根本没机会执行 —— 所以必须配合非阻塞 I/O 和显式挂起机制使用。

目前 Java 语言本身并未原生支持 Fiber,但我们可以通过以下几种方式引入:

4.1. Quasar

Quasar 是一个成熟的 Java/Kotlin 协程库,支持:

  • Java 11+(推荐),旧版支持 Java 8
  • 使用 Java Agent 在运行时织入 fiber 支持
  • 无需修改构建流程,启动时加 -javaagent:quasar.jar 即可

示例代码:

public class FiberExample {
    public static void main(String[] args) throws Exception {
        Fiber<Integer> fiber = new Fiber<>(() -> {
            System.out.println("Fiber 开始执行");
            Fiber.sleep(1000);
            return 42;
        }).start();

        System.out.println("主线程继续");
        System.out.println("Fiber 结果: " + fiber.get());
    }
}

✅ 优点:API 简洁,与 Kotlin 协程兼容性好
❌ 缺点:依赖 Java Agent,某些环境受限(如容器安全策略限制 agent 加载)

4.2. Kilim

Kilim 是另一个轻量级 fiber 实现,与 Quasar 最大的不同在于:

它使用 字节码织入(bytecode weaving) 而非 Java Agent。

这意味着:

  • 在编译期修改 class 文件,插入调度逻辑
  • 运行时不依赖 agent,更适合生产环境
  • 支持 Java 7+

示例任务定义:

public class MyTask extends Task {
    public void run() throws Pausable {
        System.out.println("Task 开始");
        pause(); // 主动挂起
        System.out.println("Task 恢复");
    }
}

✅ 适用场景:不能用 agent 的项目、对运行时纯净性要求高的系统
⚠️ 踩坑提示:构建流程需集成 weave 插件(如 Maven 插件),配置稍复杂

4.3. Project Loom

Project Loom 是 OpenJDK 官方推动的一个实验性项目,目标是将 Fiber 直接集成进 JVM,提供原生级别的轻量级并发支持。

核心特性包括:

  • 新增 java.lang.Thread 的新实现模式(虚拟线程)
  • 兼容现有 Thread API,无需重写代码
  • 不再需要 Java Agent 或字节码织入
  • 极大提升并发吞吐量(单机支持百万级并发)

🔔 注意:截至 JDK 21,Loom 已进入预览阶段(Preview Feature),可通过启动参数开启:

--enable-preview --source 21

示例代码(虚拟线程):

public class VirtualThreadExample {
    public static void main(String[] args) {
        Thread.startVirtualThread(() -> {
            System.out.println("我在虚拟线程中运行");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {}
            System.out.println("虚拟线程结束");
        });
    }
}

✅ 展望未来:Loom 很可能成为 Java 下一代并发模型的基础,一旦正式发布,将彻底改变我们编写高并发服务的方式。

5. 协程(Coroutines)

协程可以理解为“没有调度器的 fiber”——它的执行流程完全由调用方控制

✅ 协程本质是一段可暂停、可恢复的函数,yield 时保存状态,下次 resume 时从中断处继续。

典型使用模式如下:

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        for (i in 1..3) {
            print("协程输出 $i ")
            yield() // 主动让出
        }
    }

    repeat(3) {
        println("主流程工作")
        delay(100)
    }
}

输出可能为:

协程输出 1 主流程工作
协程输出 2 主流程工作
协程输出 3 主流程工作

📌 关键点:

  • Kotlin 原生支持协程(kotlinx.coroutines
  • Java 没有语言级支持,但可通过 Quasar 等库模拟
  • 更适合流程控制类场景(如状态机、生成器),而非大规模并发 I/O

对比总结:

特性 原生线程 Fiber 协程
调度方式 抢占式 协作式 手动控制
并发规模 数千 数十万 中等
使用难度 简单 中等 中等
是否需要特殊支持 是(Agent/Weave/JVM 改造) 是(语言或库)

6. 总结

Java 的并发演进路径清晰可见:

从原生线程 → 第三方 fiber 库(Quasar/Kilim) → JVM 原生支持(Project Loom)→ 协程补充控制流

📌 当前建议:

  • ✅ 普通业务:继续使用 ExecutorService + 原生线程池
  • ✅ 高并发 I/O 密集型服务:关注 Project Loom 虚拟线程,尽早试用预览版
  • ✅ 流程控制复杂逻辑:考虑 Kotlin 协程或 Quasar
  • ❌ 不要尝试自己实现绿色线程或 fiber 调度器,容易踩坑且性能难保障

🔥 下一步行动:下载 JDK 21+,开启 --enable-preview,亲手体验一把百万并发的丝滑感。


原始标题:Threading Models in Java