简单例子
class Test {
fun test() {
GlobalScope.launch {//启动协程
println("Hello!")
delay(1000L)
println("World!")
}
}
}
反编译代码
public final class Test {
public final void test() {
BuildersKt.launch$default((CoroutineScope) GlobalScope.INSTANCE,
null, null,
new LaunchUnderTheHoodKt$testLaunch$1(null), 3, null);//1
}
static final class LaunchUnderTheHoodKt$testLaunch$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {//2
int label;//3
LaunchUnderTheHoodKt$testLaunch$1(Continuation $completion) {
super(2, $completion);
}
@Nullable
@Override
public final Object invokeSuspend(@NotNull Object $result) {//4
Object object = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0://5
System.out.println("Hello!");
this.label = 1;
if (DelayKt.delay(1000L, (Continuation) this) == object) return object;
DelayKt.delay(1000L, (Continuation) this);
System.out.println("World!");
return Unit.INSTANCE;
case 1://6
System.out.println("World!");
return Unit.INSTANCE;
}
}
@Override
public final Object invoke(@NotNull CoroutineScope p1, @Nullable Continuation p2) {//7
return ((LaunchUnderTheHoodKt$testLaunch$1) create(p1, p2)).invokeSuspend(Unit.INSTANCE);
}
@NonNull
@Override
public final Continuation create(@Nullable Object value, @NotNull Continuation $completion) {//8
return (Continuation) new LaunchUnderTheHoodKt$testLaunch$1($completion);
}
}
}
反编译后的代码有点吓人,我一开始也看蒙,抓住重点,慢慢看,还是能发现一点东西的。
- 注释1:对应GlobalScope.launch启动协程,类LaunchUnderTheHoodKt1为协程体的实现,后面重点分析它;
- 注释2:LaunchUnderTheHoodKt1继承SuspendLambda,实现Function2接口;
- 注释3:LaunchUnderTheHoodKt1有一个label属性,它标记当前状态,它就是大名鼎鼎的状态机,invokeSuspend函数根据label执行不同的状态代码,例4中lable有两个值,0跟1;
- 注释4:重新invokeSuspend接口,它是BaseContinuationImpl中定义,当协程启动,函数会被调用;
- 注释5:label初始值为0,所以先执行println("Hello!"),并把label赋值为1以便状态流程到case 1,当执行到delay函数,invokeSuspend函数就返回,这里就是常说的挂起;
- 注释6:当dalay函数恢复,invokeSuspend函数会被再次触发,这里就是常说的恢复,此时label为1,所以执行println("World!"),至此整个协程执行完毕;
- 注释7:负责协程体对象的创建以及启动;
- 注释8:负责协程体对象的创建;
为什么Delay函数恢复后能回到LaunchUnderTheHoodKt1呢?
switch (this.label) {
case 0:
System.out.println("Hello!");
this.label = 1;
if (DelayKt.delay(1000L, (Continuation) this) == object) return object;//1
DelayKt.delay(1000L, (Continuation) this);
System.out.println("World!");
return Unit.INSTANCE;
case 1:
System.out.println("World!");
return Unit.INSTANCE;
}
- 注释1:执行delay函数时,把协程体this传入delay函数,当恢复时会触发invokeSuspend函数,接着执行后续代码。
协程体LaunchUnderTheHoodKt1关系图
协程体LaunchUnderTheHoodKt1流程图
总结
- 协程体的lambda表达式,通过Kotlin编译器会转换成内部类LaunchUnderTheHoodKt1,所以它本质也是一个对象;
- LaunchUnderTheHoodKt1 create负责对象创建,invokeSuspend负责执行协程体逻辑;
- LaunchUnderTheHoodKt1 label负责状态机的状态流转;
- 以上反编译代码经过删减,不过大概能表达协程体的本质;
有上述概念,分析协程创建、启动原理就容易多了 juejin.cn/editor/draf…