Android 线程创建背后的 "团队组建" 故事:从 Java 到 Linux 的协作之旅

48 阅读4分钟

一、线程王国的三种 "团队" 类型

在 Android 系统这个大工厂里,有三种专门负责执行任务的 "团队"(线程):

  1. Java 开发团队:主要用 Java 语言编写任务,需要虚拟机(VM)提供运行环境

  2. 本地 C/C++ 团队:只处理 C/C++ 任务,分为两种:

    • 普通本地团队:不与 Java 团队打交道

    • 全能本地团队:既能处理 C/C++,又能调用 Java 团队的资源

这三类团队的组建流程各不相同,但最终都需要通过 Linux 系统申请资源,就像所有工厂团队都需要向总部(Linux 内核)申请办公场地一样。

二、Java 开发团队的组建流程(Thread.start () 的秘密)

2.1 队长下令:"开始组建团队!"

java

// Java队长(Thread类)发布命令
public synchronized void start() {
    checkNotStarted(); // 检查是否重复组建
    hasBeenStarted = true;
    nativeCreate(this, stackSize, daemon); // 通知底层团队组建
}

故事场景:Java 队长(Thread)拿着计划书找到翻译官(JNI),说:"需要组建一个新团队,配置是这样的..."

2.2 翻译官的任务单(JNI 层的转发)

cpp

运行

// 翻译官(java_lang_Thread.cc)的任务单
static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread,
                              jlong stack_size, jboolean daemon) {
  Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
}

故事场景:翻译官(JNI)把 Java 队长的需求翻译成底层能听懂的语言,交给虚拟机团队的负责人。

2.3 虚拟机团队的组建工作

cpp

运行

// 虚拟机团队负责人(thread.cc)的操作
void Thread::CreateNativeThread(...) {
  Thread* child_thread = new Thread(is_daemon); // 新建团队档案
  // 记录团队对应的Java队长
  env->SetLongField(java_peer, ..., reinterpret_cast<jlong>(child_thread));
  
  pthread_attr_t attr;
  // 核心:向Linux总部申请资源创建团队
  pthread_create(&new_pthread, &attr, Thread::CreateCallback, child_thread);
}

故事场景:虚拟机团队负责人拿到需求后,先创建团队档案(Thread 对象),然后拿出正式申请单(pthread_create),向 Linux 总部申请办公场地和资源。

2.4 Linux 总部的资源分配(pthread_create 的本质)

pthread_create 最终会调用 Linux 的 clone 系统调用,就像总部打开仓库大门,分配办公桌椅(内存栈)、指定团队领导(线程函数),让新团队正式运转起来。

三、本地 C/C++ 团队的组建:两种不同的 "工种"

3.1 普通本地团队:只干 C/C++ 的活

cpp

运行

// 团队领导(Threads.cpp)的招聘流程
status_t Thread::run(...) {
    if (mCanCallJava == false) {
        // 普通本地团队:不需要Java能力
        res = androidCreateRawThreadEtc(_threadLoop, this, ...);
    }
}

int androidCreateRawThreadEtc(...) {
    pthread_attr_t attr;
    // 配置团队属性(如办公面积stackSize)
    pthread_create(&thread, &attr, entryFunction, userData);
}

故事场景:团队领导说 "我们只做 C/C++ 任务,不需要和 Java 部门打交道",直接向 Linux 总部申请资源,组建纯本地团队,团队核心工作是循环执行 threadLoop 任务。

3.2 全能本地团队:既能干 C/C++ 又能调用 Java

cpp

运行

// 全能团队的特殊招聘流程
bool createThreadEtc(...) {
    return androidCreateThreadEtc(..., ...); // 调用到Java相关流程
}

int AndroidRuntime::javaCreateThreadEtc(...) {
    // 准备参数:任务函数、用户数据、团队名称
    result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args, ...);
}

int AndroidRuntime::javaThreadShell(void* args) {
    // 关键1:加入Java协会(attach到虚拟机)
    if (javaAttachThread(name, &env) != JNI_OK) return -1;
    
    // 执行C/C++任务
    result = (*(android_thread_func_t)start)(userData);
    
    // 关键2:退出Java协会(detach from虚拟机)
    javaDetachThread();
}

故事场景:这类团队需要特殊技能 —— 能看懂 Java 文件。所以组建时多了两步:

  1. 入职时先加入 Java 协会(javaAttachThread),获得阅读 Java 文件的权限
  2. 离职时退出协会(javaDetachThread),归还权限
    中间执行任务时,既能处理 C/C++ 工作(threadLoop),又能通过协会翻译调用 Java 资源。

四、三类团队的核心共同点:都要找 Linux 总部 "盖章"

不管是 Java 团队、普通本地团队还是全能本地团队,最终组建的关键一步都是:

cpp

运行

pthread_create(&thread, &attr, entryFunction, userData);

这就像所有团队组建都需要拿着申请书到 Linux 总部盖章,总部根据申请分配资源(内存、CPU 时间片等),最终生成一个真正干活的线程实体。

区别在于:

  • Java 团队:由虚拟机团队包装后申请
  • 普通本地团队:直接申请,不涉及 Java
  • 全能本地团队:申请时带着 "Java 协会会员证"(attach/detach 流程)

五、故事总结:线程创建的 "工厂模型"

  1. Java 线程:Java 队长 -> 翻译官(JNI)-> 虚拟机团队 -> Linux 总部

  2. 普通本地线程:本地团队领导 -> Linux 总部

  3. 全能本地线程:本地团队领导 -> "Java 协会中介" -> Linux 总部

所有团队的 "工牌"(线程 ID)最终都由 Linux 总部发放,而能否处理 Java 任务,取决于是否经过 "Java 协会" 的认证(attach/detach 流程)。通过这种分层协作,Android 系统实现了不同语言线程的统一管理和资源分配。