前言
協(xié)程是Koltin語言最重要的特性之一,也是最難理解的特性。網(wǎng)上關(guān)于kotlin協(xié)程的描述也是五花八門,有人說它是輕量級(jí)線程,有人說它是無阻塞式掛起,有人說它是一個(gè)異步框架等等,眾說紛蕓。甚至還有人出了書籍專門介紹kotlin協(xié)程。
筆者剛開始接觸這個(gè)概念也是一頭霧水:什么叫輕量級(jí)線程?難道它是一個(gè)操作系統(tǒng)級(jí)別的任務(wù)調(diào)度器嗎?聞所未聞呀。
后來才知道協(xié)程它其實(shí)不是線程,它只是一個(gè)語言層面的東西,確切地講它是一個(gè)輕量級(jí)的線程框架,主要功能是可以實(shí)現(xiàn)簡(jiǎn)潔的線程切換,避免了直接使用Thread導(dǎo)致的回調(diào)地獄。也可以說它用同步的方式實(shí)現(xiàn)異步操作。
看別人怎么介紹,還不如親眼看一看協(xié)程的字節(jié)碼,其實(shí)沒那么難。
筆者原創(chuàng),轉(zhuǎn)載請(qǐng)注明來源:https://blog.csdn.net/devnn/article/details/135610313
協(xié)程字節(jié)碼
在MainActivity的onCreate
中寫一段協(xié)程的代碼:
lifecycleScope.launchWhenResumed {
Log.i("MainActivity", "launchWhenResumed,isMainThread:${Thread.currentThread().id == Looper.getMainLooper().thread.id}")//這里打印true
Log.i("MainActivity", "launchWhenResumed,threadId:${Thread.currentThread().id}")//這里threadId打印2也就是主線程
//以下兩個(gè)代碼塊是串行執(zhí)行的
withContext(Dispatchers.Main) {
Thread.sleep(10000)
Log.i("MainActivity", "launchWhenResumed,withContext1,threadId:${Thread.currentThread().id}")
}
withContext(Dispatchers.IO) {
Log.i("MainActivity", "launchWhenResumed,withContext2,threadId:${Thread.currentThread().id}")
}
}
筆者用lifecycleScope
創(chuàng)建了一個(gè)協(xié)程,用其它方式創(chuàng)建也是一樣的,比如MainScope()、GlobalScope、viewModelScope等等,這些方式的區(qū)別不是本文介紹的重點(diǎn)。
以上代碼的字節(jié)碼內(nèi)容如下:
L33
LINENUMBER 126 L33
ALOAD 0
CHECKCAST androidx/lifecycle/LifecycleOwner
INVOKESTATIC androidx/lifecycle/LifecycleOwnerKt.getLifecycleScope (Landroidx/lifecycle/LifecycleOwner;)Landroidx/lifecycle/LifecycleCoroutineScope;
NEW com/devnn/demo/MainActivity$onCreate$6
DUP
ACONST_NULL
INVOKESPECIAL com/devnn/demo/MainActivity$onCreate$6.<init> (Lkotlin/coroutines/Continuation;)V
CHECKCAST kotlin/jvm/functions/Function2
INVOKEVIRTUAL androidx/lifecycle/LifecycleCoroutineScope.launchWhenResumed (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
POP
協(xié)程代碼塊被封裝成了一個(gè)匿名內(nèi)部類,匿名內(nèi)部類繼承了SuspendLambda
(它實(shí)現(xiàn)了Continuation
接口),同時(shí)實(shí)現(xiàn)了Function2接口,匿名內(nèi)部類的構(gòu)造方法需要一個(gè)Continuation參數(shù),以上傳null。
這個(gè)匿名內(nèi)部類com/devnn/demo/MainActivity\$onCreate\$6.class
內(nèi)容如下:
final class com.devnn.demo.MainActivity$onCreate$6 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>, java.lang.Object> {
int label;
com.devnn.demo.MainActivity$onCreate$6(kotlin.coroutines.Continuation<? super com.devnn.demo.MainActivity$onCreate$6>);
Code:
0: aload_0
1: iconst_2
2: aload_1
3: invokespecial #13 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V
6: return
public final java.lang.Object invokeSuspend(java.lang.Object);
Code:
0: invokestatic #39 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;
3: astore_2
4: aload_0
5: getfield #43 // Field label:I
8: tableswitch { // 0 to 2
0: 36
1: 134
2: 176
default: 186
}
36: aload_1
37: invokestatic #49 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
40: ldc #51 // String MainActivity
42: ldc #53 // String launchWhenResumed,isMainThread:
44: invokestatic #59 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
47: invokevirtual #63 // Method java/lang/Thread.getId:()J
50: invokestatic #69 // Method android/os/Looper.getMainLooper:()Landroid/os/Looper;
53: invokevirtual #72 // Method android/os/Looper.getThread:()Ljava/lang/Thread;
56: invokevirtual #63 // Method java/lang/Thread.getId:()J
59: lcmp
60: ifne 67
63: iconst_1
64: goto 68
67: iconst_0
68: invokestatic #78 // Method kotlin/coroutines/jvm/internal/Boxing.boxBoolean:(Z)Ljava/lang/Boolean;
71: invokestatic #84 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
74: invokestatic #89 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I
77: pop
78: ldc #51 // String MainActivity
80: ldc #91 // String launchWhenResumed,threadId:
82: invokestatic #59 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
85: invokevirtual #63 // Method java/lang/Thread.getId:()J
88: invokestatic #95 // Method kotlin/coroutines/jvm/internal/Boxing.boxLong:(J)Ljava/lang/Long;
91: invokestatic #84 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
94: invokestatic #89 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I
97: pop
98: invokestatic #101 // Method kotlinx/coroutines/Dispatchers.getMain:()Lkotlinx/coroutines/MainCoroutineDispatcher;
101: checkcast #103 // class kotlin/coroutines/CoroutineContext
104: new #105 // class com/devnn/demo/MainActivity$onCreate$6$1
107: dup
108: aconst_null
109: invokespecial #107 // Method com/devnn/demo/MainActivity$onCreate$6$1."<init>":(Lkotlin/coroutines/Continuation;)V
112: checkcast #7 // class kotlin/jvm/functions/Function2
115: aload_0
116: checkcast #109 // class kotlin/coroutines/Continuation
119: aload_0
120: iconst_1
121: putfield #43 // Field label:I
124: invokestatic #115 // Method kotlinx/coroutines/BuildersKt.withContext:(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
127: dup
128: aload_2
129: if_acmpne 139
132: aload_2
133: areturn
134: aload_1
135: invokestatic #49 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
138: aload_1
139: pop
140: invokestatic #119 // Method kotlinx/coroutines/Dispatchers.getIO:()Lkotlinx/coroutines/CoroutineDispatcher;
143: checkcast #103 // class kotlin/coroutines/CoroutineContext
146: new #121 // class com/devnn/demo/MainActivity$onCreate$6$2
149: dup
150: aconst_null
151: invokespecial #122 // Method com/devnn/demo/MainActivity$onCreate$6$2."<init>":(Lkotlin/coroutines/Continuation;)V
154: checkcast #7 // class kotlin/jvm/functions/Function2
157: aload_0
158: checkcast #109 // class kotlin/coroutines/Continuation
161: aload_0
162: iconst_2
163: putfield #43 // Field label:I
166: invokestatic #115 // Method kotlinx/coroutines/BuildersKt.withContext:(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
169: dup
170: aload_2
171: if_acmpne 181
174: aload_2
175: areturn
176: aload_1
177: invokestatic #49 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
180: aload_1
181: pop
182: getstatic #128 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
185: areturn
186: new #130 // class java/lang/IllegalStateException
189: dup
190: ldc #132 // String call to 'resume' before 'invoke' with coroutine
192: invokespecial #135 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
195: athrow
public final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);
Code:
0: new #2 // class com/devnn/demo/MainActivity$onCreate$6
3: dup
4: aload_2
5: invokespecial #145 // Method "<init>":(Lkotlin/coroutines/Continuation;)V
8: checkcast #109 // class kotlin/coroutines/Continuation
11: areturn
public final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);
Code:
0: aload_0
1: aload_1
2: aload_2
3: invokevirtual #151 // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
6: checkcast #2 // class com/devnn/demo/MainActivity$onCreate$6
9: getstatic #128 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
12: invokevirtual #153 // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
15: areturn
public java.lang.Object invoke(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #159 // class kotlinx/coroutines/CoroutineScope
5: aload_2
6: checkcast #109 // class kotlin/coroutines/Continuation
9: invokevirtual #161 // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
12: areturn
}
這個(gè)匿名內(nèi)部類只有一個(gè)字段就是int類型的label
。同時(shí)它的主要業(yè)務(wù)邏輯代碼在invokeSuspend
函數(shù)中,這個(gè)函數(shù)里面有一個(gè)tableswitch
的判斷,根據(jù)label的值,判斷跳轉(zhuǎn)到哪一塊代碼執(zhí)行。看這個(gè)有點(diǎn)類似有限狀態(tài)機(jī)。
Function2
接口內(nèi)容:public interface Function2<in P1, in P2, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2): R }
MainActivity的協(xié)程中有兩段withContext{}
代碼塊,它們也被封裝成了匿名內(nèi)部類,這個(gè)匿名內(nèi)部類跟外部的協(xié)程代碼塊一樣,繼承了SuspendLambda類,同時(shí)實(shí)現(xiàn)了Function2接口。
第一個(gè)withContext
代碼塊的匿名內(nèi)部類是com/devnn/demo/MainActivity\$onCreate\$6\$1.class
第二個(gè)withContext
代碼塊的匿名內(nèi)部類是com/devnn/demo/MainActivity\$onCreate\$6\$2.class
轉(zhuǎn)載請(qǐng)注明來源:
https://blog.csdn.net/devnn/article/details/135610313文章來源地址http://www.zghlxwxcb.cn/news/detail-799477.html
com/devnn/demo/MainActivity\$onCreate\$6\$1.class
的內(nèi)容如下:
final class com.devnn.demo.MainActivity$onCreate$6$1 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super java.lang.Integer>, java.lang.Object> {
int label;
com.devnn.demo.MainActivity$onCreate$6$1(kotlin.coroutines.Continuation<? super com.devnn.demo.MainActivity$onCreate$6$1>);
Code:
0: aload_0
1: iconst_2
2: aload_1
3: invokespecial #13 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V
6: return
public final java.lang.Object invokeSuspend(java.lang.Object);
Code:
0: invokestatic #37 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;
3: pop
4: aload_0
5: getfield #41 // Field label:I
8: tableswitch { // 0 to 0
0: 28
default: 61
}
28: aload_1
29: invokestatic #47 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
32: ldc2_w #48 // long 10000l
35: invokestatic #55 // Method java/lang/Thread.sleep:(J)V
38: ldc #57 // String MainActivity
40: ldc #59 // String launchWhenResumed,withContext1,threadId:
42: invokestatic #63 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
45: invokevirtual #67 // Method java/lang/Thread.getId:()J
48: invokestatic #73 // Method kotlin/coroutines/jvm/internal/Boxing.boxLong:(J)Ljava/lang/Long;
51: invokestatic #79 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
54: invokestatic #84 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I
57: invokestatic #88 // Method kotlin/coroutines/jvm/internal/Boxing.boxInt:(I)Ljava/lang/Integer;
60: areturn
61: new #90 // class java/lang/IllegalStateException
64: dup
65: ldc #92 // String call to 'resume' before 'invoke' with coroutine
67: invokespecial #95 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
70: athrow
public final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);
Code:
0: new #2 // class com/devnn/demo/MainActivity$onCreate$6$1
3: dup
4: aload_2
5: invokespecial #102 // Method "<init>":(Lkotlin/coroutines/Continuation;)V
8: checkcast #104 // class kotlin/coroutines/Continuation
11: areturn
public final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super java.lang.Integer>);
Code:
0: aload_0
1: aload_1
2: aload_2
3: invokevirtual #110 // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
6: checkcast #2 // class com/devnn/demo/MainActivity$onCreate$6$1
9: getstatic #116 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
12: invokevirtual #118 // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
15: areturn
public java.lang.Object invoke(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #124 // class kotlinx/coroutines/CoroutineScope
5: aload_2
6: checkcast #104 // class kotlin/coroutines/Continuation
9: invokevirtual #126 // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
12: areturn
}
com.devnn.demo.MainActivity$onCreate$6$2
的內(nèi)容如下:
final class com.devnn.demo.MainActivity$onCreate$6$2 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>, java.lang.Object> {
int label;
com.devnn.demo.MainActivity$onCreate$6$2(kotlin.coroutines.Continuation<? super com.devnn.demo.MainActivity$onCreate$6$2>);
Code:
0: aload_0
1: iconst_2
2: aload_1
3: invokespecial #13 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V
6: return
public final java.lang.Object invokeSuspend(java.lang.Object);
Code:
0: invokestatic #37 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;
3: pop
4: aload_0
5: getfield #41 // Field label:I
8: tableswitch { // 0 to 0
0: 28
default: 56
}
28: aload_1
29: invokestatic #47 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V
32: ldc #49 // String MainActivity
34: ldc #51 // String launchWhenResumed,withContext2,threadId:
36: invokestatic #57 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
39: invokevirtual #61 // Method java/lang/Thread.getId:()J
42: invokestatic #67 // Method kotlin/coroutines/jvm/internal/Boxing.boxLong:(J)Ljava/lang/Long;
45: invokestatic #73 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
48: invokestatic #78 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I
51: pop
52: getstatic #84 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
55: areturn
56: new #86 // class java/lang/IllegalStateException
59: dup
60: ldc #88 // String call to 'resume' before 'invoke' with coroutine
62: invokespecial #91 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
65: athrow
public final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);
Code:
0: new #2 // class com/devnn/demo/MainActivity$onCreate$6$2
3: dup
4: aload_2
5: invokespecial #98 // Method "<init>":(Lkotlin/coroutines/Continuation;)V
8: checkcast #100 // class kotlin/coroutines/Continuation
11: areturn
public final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);
Code:
0: aload_0
1: aload_1
2: aload_2
3: invokevirtual #106 // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
6: checkcast #2 // class com/devnn/demo/MainActivity$onCreate$6$2
9: getstatic #84 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
12: invokevirtual #108 // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
15: areturn
public java.lang.Object invoke(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #114 // class kotlinx/coroutines/CoroutineScope
5: aload_2
6: checkcast #100 // class kotlin/coroutines/Continuation
9: invokevirtual #116 // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
12: areturn
}
每次執(zhí)行新的匿名內(nèi)部類代碼(就是withContext
代碼塊)時(shí),就把當(dāng)前這個(gè)匿名內(nèi)部類傳遞給了新的匿名內(nèi)部類。注意每個(gè)匿名內(nèi)部類都是Continuation的實(shí)現(xiàn)??吹竭@里就知道其實(shí)Continuation就是一個(gè)回調(diào)。這其實(shí)就跟Java的回調(diào)一樣,只是Kotlin隱式地實(shí)現(xiàn)了回調(diào),并且加了狀態(tài)機(jī)機(jī)制。每次執(zhí)行一段suspend代碼之后,將狀態(tài)值修改成新值,執(zhí)行回調(diào)時(shí)就知道走哪一段代碼塊。文章來源:http://www.zghlxwxcb.cn/news/detail-799477.html
轉(zhuǎn)載請(qǐng)注明來源:
https://blog.csdn.net/devnn/article/details/135610313
到了這里,關(guān)于【Kotlin】協(xié)程的字節(jié)碼原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!