【Kotlin】协程的字节码原理

前言

协程是Koltin语言最重要的特性之一,也是最难理解的特性。网上关于kotlin协程的描述也是五花八门,有人说它是轻量级线程,有人说它是无阻塞式挂起,有人说它是一个异步框架等等,众说纷芸。甚至还有人出了书籍专门介绍kotlin协程。

笔者刚开始接触这个概念也是一头雾水:什么叫轻量级线程?难道它是一个操作系统级别的任务调度器吗?闻所未闻呀。

后来才知道协程它其实不是线程,它只是一个语言层面的东西,确切地讲它是一个轻量级的线程框架,主要功能是可以实现简洁的线程切换,避免了直接使用Thread导致的回调地狱。也可以说它用同步的方式实现异步操作。

看别人怎么介绍,还不如亲眼看一看协程的字节码,其实没那么难。

在这里插入图片描述
笔者原创,转载请注明来源:https://blog.csdn.net/devnn/article/details/135610313

协程字节码

在MainActivity的onCreate中写一段协程的代码:

lifecycleScope.launchWhenResumed {Log.i("MainActivity", "launchWhenResumed,isMainThread:${Thread.currentThread().id == Looper.getMainLooper().thread.id}")//这里打印trueLog.i("MainActivity", "launchWhenResumed,threadId:${Thread.currentThread().id}")//这里threadId打印2也就是主线程//以下两个代码块是串行执行的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创建了一个协程,用其它方式创建也是一样的,比如MainScope()、GlobalScope、viewModelScope等等,这些方式的区别不是本文介绍的重点。

以上代码的字节码内容如下:

 L33LINENUMBER 126 L33ALOAD 0CHECKCAST androidx/lifecycle/LifecycleOwnerINVOKESTATIC androidx/lifecycle/LifecycleOwnerKt.getLifecycleScope (Landroidx/lifecycle/LifecycleOwner;)Landroidx/lifecycle/LifecycleCoroutineScope;NEW com/devnn/demo/MainActivity$onCreate$6DUPACONST_NULLINVOKESPECIAL com/devnn/demo/MainActivity$onCreate$6.<init> (Lkotlin/coroutines/Continuation;)VCHECKCAST kotlin/jvm/functions/Function2INVOKEVIRTUAL androidx/lifecycle/LifecycleCoroutineScope.launchWhenResumed (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;POP

协程代码块被封装成了一个匿名内部类,匿名内部类继承了SuspendLambda(它实现了Continuation接口),同时实现了Function2接口,匿名内部类的构造方法需要一个Continuation参数,以上传null。

这个匿名内部类com/devnn/demo/MainActivity\$onCreate\$6.class内容如下:

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_01: iconst_22: aload_13: invokespecial #13                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V6: returnpublic final java.lang.Object invokeSuspend(java.lang.Object);Code:0: invokestatic  #39                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;3: astore_24: aload_05: getfield      #43                 // Field label:I8: tableswitch   { // 0 to 20: 361: 1342: 176default: 186}36: aload_137: invokestatic  #49                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V40: ldc           #51                 // String MainActivity42: ldc           #53                 // String launchWhenResumed,isMainThread:44: invokestatic  #59                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;47: invokevirtual #63                 // Method java/lang/Thread.getId:()J50: 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:()J59: lcmp60: ifne          6763: iconst_164: goto          6867: iconst_068: 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;)I77: pop78: ldc           #51                 // String MainActivity80: ldc           #91                 // String launchWhenResumed,threadId:82: invokestatic  #59                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;85: invokevirtual #63                 // Method java/lang/Thread.getId:()J88: 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;)I97: pop98: invokestatic  #101                // Method kotlinx/coroutines/Dispatchers.getMain:()Lkotlinx/coroutines/MainCoroutineDispatcher;101: checkcast     #103                // class kotlin/coroutines/CoroutineContext104: new           #105                // class com/devnn/demo/MainActivity$onCreate$6$1107: dup108: aconst_null109: invokespecial #107                // Method com/devnn/demo/MainActivity$onCreate$6$1."<init>":(Lkotlin/coroutines/Continuation;)V112: checkcast     #7                  // class kotlin/jvm/functions/Function2115: aload_0116: checkcast     #109                // class kotlin/coroutines/Continuation119: aload_0120: iconst_1121: putfield      #43                 // Field label:I124: invokestatic  #115                // Method kotlinx/coroutines/BuildersKt.withContext:(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;127: dup128: aload_2129: if_acmpne     139132: aload_2133: areturn134: aload_1135: invokestatic  #49                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V138: aload_1139: pop140: invokestatic  #119                // Method kotlinx/coroutines/Dispatchers.getIO:()Lkotlinx/coroutines/CoroutineDispatcher;143: checkcast     #103                // class kotlin/coroutines/CoroutineContext146: new           #121                // class com/devnn/demo/MainActivity$onCreate$6$2149: dup150: aconst_null151: invokespecial #122                // Method com/devnn/demo/MainActivity$onCreate$6$2."<init>":(Lkotlin/coroutines/Continuation;)V154: checkcast     #7                  // class kotlin/jvm/functions/Function2157: aload_0158: checkcast     #109                // class kotlin/coroutines/Continuation161: aload_0162: iconst_2163: putfield      #43                 // Field label:I166: invokestatic  #115                // Method kotlinx/coroutines/BuildersKt.withContext:(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;169: dup170: aload_2171: if_acmpne     181174: aload_2175: areturn176: aload_1177: invokestatic  #49                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V180: aload_1181: pop182: getstatic     #128                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;185: areturn186: new           #130                // class java/lang/IllegalStateException189: dup190: ldc           #132                // String call to 'resume' before 'invoke' with coroutine192: invokespecial #135                // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V195: athrowpublic final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);Code:0: new           #2                  // class com/devnn/demo/MainActivity$onCreate$63: dup4: aload_25: invokespecial #145                // Method "<init>":(Lkotlin/coroutines/Continuation;)V8: checkcast     #109                // class kotlin/coroutines/Continuation11: areturnpublic final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);Code:0: aload_01: aload_12: aload_23: invokevirtual #151                // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;6: checkcast     #2                  // class com/devnn/demo/MainActivity$onCreate$69: getstatic     #128                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;12: invokevirtual #153                // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;15: areturnpublic java.lang.Object invoke(java.lang.Object, java.lang.Object);Code:0: aload_01: aload_12: checkcast     #159                // class kotlinx/coroutines/CoroutineScope5: aload_26: checkcast     #109                // class kotlin/coroutines/Continuation9: invokevirtual #161                // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;12: areturn
}

这个匿名内部类只有一个字段就是int类型的label。同时它的主要业务逻辑代码在invokeSuspend函数中,这个函数里面有一个tableswitch的判断,根据label的值,判断跳转到哪一块代码执行。看这个有点类似有限状态机。

Function2接口内容:

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的协程中有两段withContext{}代码块,它们也被封装成了匿名内部类,这个匿名内部类跟外部的协程代码块一样,继承了SuspendLambda类,同时实现了Function2接口。

第一个withContext代码块的匿名内部类是com/devnn/demo/MainActivity\$onCreate\$6\$1.class

第二个withContext代码块的匿名内部类是com/devnn/demo/MainActivity\$onCreate\$6\$2.class

转载请注明来源:
https://blog.csdn.net/devnn/article/details/135610313

com/devnn/demo/MainActivity\$onCreate\$6\$1.class的内容如下:

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_01: iconst_22: aload_13: invokespecial #13                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V6: returnpublic final java.lang.Object invokeSuspend(java.lang.Object);Code:0: invokestatic  #37                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;3: pop4: aload_05: getfield      #41                 // Field label:I8: tableswitch   { // 0 to 00: 28default: 61}28: aload_129: invokestatic  #47                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V32: ldc2_w        #48                 // long 10000l35: invokestatic  #55                 // Method java/lang/Thread.sleep:(J)V38: ldc           #57                 // String MainActivity40: 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:()J48: 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;)I57: invokestatic  #88                 // Method kotlin/coroutines/jvm/internal/Boxing.boxInt:(I)Ljava/lang/Integer;60: areturn61: new           #90                 // class java/lang/IllegalStateException64: dup65: ldc           #92                 // String call to 'resume' before 'invoke' with coroutine67: invokespecial #95                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V70: athrowpublic final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);Code:0: new           #2                  // class com/devnn/demo/MainActivity$onCreate$6$13: dup4: aload_25: invokespecial #102                // Method "<init>":(Lkotlin/coroutines/Continuation;)V8: checkcast     #104                // class kotlin/coroutines/Continuation11: areturnpublic final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super java.lang.Integer>);Code:0: aload_01: aload_12: aload_23: invokevirtual #110                // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;6: checkcast     #2                  // class com/devnn/demo/MainActivity$onCreate$6$19: getstatic     #116                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;12: invokevirtual #118                // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;15: areturnpublic java.lang.Object invoke(java.lang.Object, java.lang.Object);Code:0: aload_01: aload_12: checkcast     #124                // class kotlinx/coroutines/CoroutineScope5: aload_26: checkcast     #104                // class kotlin/coroutines/Continuation9: invokevirtual #126                // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;12: areturn
}

com.devnn.demo.MainActivity$onCreate$6$2的内容如下:

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_01: iconst_22: aload_13: invokespecial #13                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V6: returnpublic final java.lang.Object invokeSuspend(java.lang.Object);Code:0: invokestatic  #37                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;3: pop4: aload_05: getfield      #41                 // Field label:I8: tableswitch   { // 0 to 00: 28default: 56}28: aload_129: invokestatic  #47                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V32: ldc           #49                 // String MainActivity34: 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:()J42: 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;)I51: pop52: getstatic     #84                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;55: areturn56: new           #86                 // class java/lang/IllegalStateException59: dup60: ldc           #88                 // String call to 'resume' before 'invoke' with coroutine62: invokespecial #91                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V65: athrowpublic final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);Code:0: new           #2                  // class com/devnn/demo/MainActivity$onCreate$6$23: dup4: aload_25: invokespecial #98                 // Method "<init>":(Lkotlin/coroutines/Continuation;)V8: checkcast     #100                // class kotlin/coroutines/Continuation11: areturnpublic final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);Code:0: aload_01: aload_12: aload_23: invokevirtual #106                // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;6: checkcast     #2                  // class com/devnn/demo/MainActivity$onCreate$6$29: getstatic     #84                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;12: invokevirtual #108                // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;15: areturnpublic java.lang.Object invoke(java.lang.Object, java.lang.Object);Code:0: aload_01: aload_12: checkcast     #114                // class kotlinx/coroutines/CoroutineScope5: aload_26: checkcast     #100                // class kotlin/coroutines/Continuation9: invokevirtual #116                // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;12: areturn
}

每次执行新的匿名内部类代码(就是withContext代码块)时,就把当前这个匿名内部类传递给了新的匿名内部类。注意每个匿名内部类都是Continuation的实现。看到这里就知道其实Continuation就是一个回调。这其实就跟Java的回调一样,只是Kotlin隐式地实现了回调,并且加了状态机机制。每次执行一段suspend代码之后,将状态值修改成新值,执行回调时就知道走哪一段代码块。

转载请注明来源:
https://blog.csdn.net/devnn/article/details/135610313

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/239310.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux用户提权

新建用户 用root账户修改文件&#xff0c;添加信任用户 使用sudo提权&#xff0c;可以使用 **root删除新建账户**

各种版本对应关系:SpringCloudAlibaba——SpringCloud——SpringBoot——SpringFramework——JDK

SpringCloudAlibaba——SpringCloud——SpringBoot——SpringFramework——JDK 一般情况&#xff0c;在https://github.com/项目/wiki目录下有发布信息及对应的要求其他依赖的版本信息SpringCloudAlibaba——SpringCloud——SpringBootSpringBoot和SpringFramework的版本对应关…

Web3的应用发展及其影响

Web3&#xff0c;又被称为去中心化Web&#xff0c;是互联网发展的一个阶段&#xff0c;其核心特点是数据的去中心化和用户自主权。近年来&#xff0c;随着区块链技术的不断成熟&#xff0c;Web3的应用也得到了广泛的关注和发展。在这篇文章中&#xff0c;我们将深入探讨Web3目前…

vuex的初步使用-1

1. 介绍 Vuex 是一个 Vue 的 状态管理工具&#xff0c;状态就是数据。 简单讲&#xff1a;Vuex 就是一个插件&#xff0c;可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。相对于一个仓库&#xff1a;存放组件共享的数据。 2. 安装 vuex 安装vuex与vue-router类似&…

LabVIEW模拟荧光显微管滑动实验

LabVIEW模拟荧光显微管滑动实验 在现代生物医学研究中&#xff0c;对微观生物过程的精准模拟和观察至关重要。本案例展示了如何利用LabVIEW软件和专业硬件平台&#xff0c;创新地模拟荧光显微管在滑动实验中的动态行为&#xff0c;这一过程不仅提升了实验效率&#xff0c;还为…

Jenkins基础篇--添加用户和用户权限设置

添加用户 点击系统管理&#xff0c;点击管理用户&#xff0c;然后点击创建用户&#xff08;Create User&#xff09; 用户权限管理 点击系统管理&#xff0c;点击全局安全配置&#xff0c;找到授权策略&#xff0c;选择安全矩阵&#xff0c;配置好用户权限后&#xff0c;点击…

C++ 开发 + VSCode 调试

C 开发 VSCode 调试 MSYS2 安装 gcc、make下载安装MSMYS2pacman 添加镜像源 GCC1. 安装2. 查看结果3. 环境变量 GDB VSCode 调试所需插件创建项目调试代码1. tasks.json 配置任务2. launch.json 配置调试3. 运行 更进一步的 C/C 设置 参考资料 MSYS2 安装 gcc、make 下载 官…

1.16云支教(集合的概念、定义)

1.集合 1.集合的概念&#xff08;意思&#xff09; 把集合理解成一个塑料袋 要往塑料袋装什么&#xff0c; 装的元素就是里面装的各个东西&#xff0c; 表示方法 1。直接穷举 A{装的到底是什么&#xff08;竹子&#xff09;} 2.描述法 描述装的东西的性质&#xff0c;…

MySQL 从零开始:03 基本入门语句

文章目录 1、连接数据库1.1 命令提示符登陆1.2 MySQL 8.0 Command Line Client 登陆1.3 MySQL Workbench 登陆 2、基本语句2.1 查看所有库2.2 创建库2.3 删除库2.4 选择数据库2.5 查看表2.6 创建表2.7 删除表2.8 改表名2.9 清空表 在上一小节中介绍了 MySQL 数据库的安装&#…

统计学-R语言-4.1

文章目录 前言编写R函数图形的控制和布局par函数layout函数 练习 前言 安装完R软件之后就可以对其进行代码的编写了。 编写R函数 如果对数据分析有些特殊需要&#xff0c;已有的R包或函数不能满足&#xff0c;可以在R中编写自己的函数。函数的定义格式如下所示&#xff1a; …

找不到mfc100.dll的解决方法,怎么修复mfc100.dll文件

当我们在使用电脑时&#xff0c;时常可能会遇到各类系统提示的错误信息。"找不到mfc100.dll" 就是这些错误之一&#xff0c;该错误提示会妨碍我们执行一些应用程序或特定代码。为了帮助读者克服这个技术障碍&#xff0c;本篇文章将详尽阐明导致该问题的根本原因&…

白码CRM快速实现报价转订单功能

某crm项目已经做到销售模块了&#xff0c;销售模块实现了从报价到销售单&#xff0c;再到财务模块的应收流程。但使用过程中发现不好用的地方&#xff1a;报价通过后客户下单&#xff0c;销售相关人员又要重新录入数据一样的销售单&#xff0c;觉得这样的操作比较繁琐&#xff…

vue3-响应式基础之reactive

reactive() 还有另一种声明响应式状态的方式&#xff0c;即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同&#xff0c;reactive() 将使对象本身具有响应性&#xff1a; 「点击按钮1」 <script lang"ts" setup> import { reactive } from vuec…

一文了解Spring线程池(超详细+干货满满)

Spring默认线程池 simpleAsyncTaskExecutor Spring异步线程池的接口类是TaskExecutor &#xff0c;本质还是 java.util.concurrent.Executor&#xff0c;没有配置的情况下&#xff0c;默认使用的是 simpleAsyncTaskExecutor Component EnableAsync public class ScheduleTask…

如何理解产品经理和项目经理的区别?

最近很多人咨询“项目经理跟产品经理该怎么选&#xff0c;我更适合哪个&#xff1f;”“项目经理跟产品经理哪个更有钱途 ”等等&#xff0c;今天就一次性说清楚项目经理跟产品经理有什么区别&#xff0c;应该怎么选择。 不想看长篇大论的&#xff0c;来找我&#xff0c;直接把…

2023年上半年软件设计师下午真题及答案解析

试题一(15分) 随着农业领域科学种植的发展&#xff0c;需要对农业基地及农事进行信息化管理&#xff0c;为租户和农户等人员提供种植相关服务&#xff0c;现欲开发农事管理服务平台&#xff0c;其主要功能是&#xff1a; (1)人员管理&#xff1a;平台管理员管理租户&#xff…

在linux环境下安装lnmp

lnmp官网&#xff1a;https://lnmp.org 一&#xff1a;lnmp安装 参考&#xff1a;https://lnmp.org/install.html 1&#xff1a;下载lnmp安装包 wget https://soft.lnmp.com/lnmp/lnmp2.0.tar.gz -O lnmp2.0.tar.gz 2&#xff1a;解压lnmp安装包 tar zxf lnmp2.0.tar.gz …

Python-高阶函数

在Python中&#xff0c;高阶函数是指能够接收函数作为参数&#xff0c;或者能够返回函数的函数。这种特性使得函数在Python中可以被灵活地传递和使用。以下是一些关于Python高阶函数的详细解释&#xff1a; 函数作为参数&#xff1a; 高阶函数可以接收其他函数作为参数。这样的…

C++多线程学习[四]:多线程的通信和同步、互斥锁、超时锁、共享锁

一、多线程的状态 初始化 &#xff08;Init&#xff09;&#xff1a;该线程正在被创建。就绪 &#xff08;Ready&#xff09;&#xff1a;该线程在就绪列表中&#xff0c;等待CPU的调度。运行 &#xff08;Running&#xff09;&#xff1a;该线程正在运行。阻塞&#xff08;Bl…

**登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**

用户登录——>数据加密数据库比对——>生成jwt令牌封装返回——>拦截器统一拦截进行jwt校验-并将数据放入本地线程中。 0、 ThreadLocal 介绍&#xff1a; ThreadLocal 并不是一个Thread&#xff0c;而是Thread的线程局部变量。 ThreadLocal为每个线程提供单独一份…