一、线程王国的三种 "团队" 类型
在 Android 系统这个大工厂里,有三种专门负责执行任务的 "团队"(线程):
-
Java 开发团队:主要用 Java 语言编写任务,需要虚拟机(VM)提供运行环境
-
本地 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 文件。所以组建时多了两步:
- 入职时先加入 Java 协会(javaAttachThread),获得阅读 Java 文件的权限
- 离职时退出协会(javaDetachThread),归还权限
中间执行任务时,既能处理 C/C++ 工作(threadLoop),又能通过协会翻译调用 Java 资源。
四、三类团队的核心共同点:都要找 Linux 总部 "盖章"
不管是 Java 团队、普通本地团队还是全能本地团队,最终组建的关键一步都是:
cpp
运行
pthread_create(&thread, &attr, entryFunction, userData);
这就像所有团队组建都需要拿着申请书到 Linux 总部盖章,总部根据申请分配资源(内存、CPU 时间片等),最终生成一个真正干活的线程实体。
区别在于:
- Java 团队:由虚拟机团队包装后申请
- 普通本地团队:直接申请,不涉及 Java
- 全能本地团队:申请时带着 "Java 协会会员证"(attach/detach 流程)
五、故事总结:线程创建的 "工厂模型"
-
Java 线程:Java 队长 -> 翻译官(JNI)-> 虚拟机团队 -> Linux 总部
-
普通本地线程:本地团队领导 -> Linux 总部
-
全能本地线程:本地团队领导 -> "Java 协会中介" -> Linux 总部
所有团队的 "工牌"(线程 ID)最终都由 Linux 总部发放,而能否处理 Java 任务,取决于是否经过 "Java 协会" 的认证(attach/detach 流程)。通过这种分层协作,Android 系统实现了不同语言线程的统一管理和资源分配。