kotlinx.coroutines 是由 JetBrains 开发的功能丰富的协程库。它包含本指南中涵盖的很多启用高级协程的原语,包括 launch、 async 等等。
本文是通过反编译协程相关class文件,分析协程的实现原理。
第一个基本协程代码
import kotlinx.coroutines.*
fun main() {
println("Starting...")
GlobalScope.launch {
repeat(10) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
println("Hello,")
Thread.sleep(20000L)
}
输出结果
Starting...
Hello,
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
I'm sleeping 3 ...
I'm sleeping 4 ...
I'm sleeping 5 ...
I'm sleeping 6 ...
I'm sleeping 7 ...
I'm sleeping 8 ...
I'm sleeping 9 ...
T1.kt编译后出现两个class文件T1kt.class和T1kt$main$1.class
public final class T1Kt {
public static final void main();
Code:
0: ldc #11 // String Starting...
2: astore_0
3: iconst_0
4: istore_1
5: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
8: aload_0
9: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
12: getstatic #29 // Field kotlinx/coroutines/GlobalScope.INSTANCE:Lkotlinx/coroutines/GlobalScope;
15: checkcast #31 // class kotlinx/coroutines/CoroutineScope
18: aconst_null
19: aconst_null
20: new #33 // class T1Kt$main$1
23: dup
24: aconst_null
25: invokespecial #37 // Method T1Kt$main$1."":(Lkotlin/coroutines/Continuation;)V
28: checkcast #39 // class kotlin/jvm/functions/Function2
31: iconst_3
32: aconst_null
33: invokestatic #45 // Method kotlinx/coroutines/BuildersKt.launch$default:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
36: pop
37: ldc #47 // String Hello,
39: astore_0
40: iconst_0
41: istore_1
42: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
45: aload_0
46: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
49: ldc2_w #48 // long 20000l
52: invokestatic #55 // Method java/lang/Thread.sleep:(J)V
55: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #9 // Method main:()V
3: return
}
自动创建了public static void main(java.lang.String[]) main方法,通过invokestatic字节码调用public static final void main方法。
此方法对应于T1.kt中的fun main方法
BuildersKt.launch方法的入参为CoroutineScope、CoroutineContext、CoroutineStart、Function2、Object。在此场景下:
T1kt$main$1继承了抽象类kotlin.coroutines.jvm.internal.SuspendLambda,并实现了接口kotlin.jvm.functions.Function2
协程执行入口
0: aload_0
1: aload_1
2: aload_2
3: checkcast #149 // class kotlin/coroutines/Continuation
6: invokevirtual #151 // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
9: checkcast #2 // class T1Kt$main$1
12: getstatic #109 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
15: invokevirtual #153 // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
18: areturn
本方法为协程的具体执行逻辑。
0: invokestatic #34 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;
3: astore 11
5: aload_0
6: getfield #37 // Field label:I
9: tableswitch { // 0 to 1
0: 32
1: 156
default: 190
}
32: aload_1
33: invokestatic #43 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
36: aload_0
37: getfield #45 // Field p$:Lkotlinx/coroutines/CoroutineScope;
40: astore_2
41: bipush 10
43: istore_3
44: iconst_0
45: istore 4
47: iconst_0
48: istore 5
50: iconst_0
51: istore 5
53: iload_3
54: istore 6
56: iload 5
58: iload 6
60: if_icmpge 186
63: iload 5
65: invokestatic #51 // Method kotlin/coroutines/jvm/internal/Boxing.boxInt:(I)Ljava/lang/Integer;
68: checkcast #53 // class java/lang/Number
71: invokevirtual #57 // Method java/lang/Number.intValue:()I
74: istore 7
76: iconst_0
77: istore 8
79: new #59 // class java/lang/StringBuilder
82: dup
83: invokespecial #63 // Method java/lang/StringBuilder."":()V
86: ldc #65 // String I'm sleeping
88: invokevirtual #69 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
91: iload 7
93: invokevirtual #72 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
96: ldc #74 // String ...
98: invokevirtual #69 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
101: invokevirtual #78 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
104: astore 9
106: iconst_0
107: istore 10
109: getstatic #84 // Field java/lang/System.out:Ljava/io/PrintStream;
112: aload 9
114: invokevirtual #89 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
117: ldc2_w #90 // long 500l
120: aload_0
121: aload_0
122: iload 5
124: putfield #93 // Field I$0:I
127: aload_0
128: iload 6
130: putfield #95 // Field I$1:I
133: aload_0
134: iload 7
136: putfield #97 // Field I$2:I
139: aload_0
140: iconst_1
141: putfield #37 // Field label:I
144: invokestatic #103 // Method kotlinx/coroutines/DelayKt.delay:(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
147: dup
148: aload 11
150: if_acmpne 179
153: aload 11
155: areturn
156: aload_0
157: getfield #97 // Field I$2:I
160: istore 7
162: aload_0
163: getfield #95 // Field I$1:I
166: istore 6
168: aload_0
169: getfield #93 // Field I$0:I
172: istore 5
174: aload_1
175: invokestatic #43 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
178: aload_1
179: pop
180: iinc 5, 1
183: goto 56
186: getstatic #109 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
189: areturn
190: new #111 // class java/lang/IllegalStateException
193: dup
194: ldc #113 // String call to 'resume' before 'invoke' with coroutine
196: invokespecial #116 // Method java/lang/IllegalStateException."":(Ljava/lang/String;)V
199: athrow