枯燥的Kotlin协程三部曲(上)——概念启蒙篇(中)

简介: Kotlin 1.3 版本开始引入协程 Coroutine,简练的官方文档 和 网上一堆浅尝辄止的文章让我心里没底,不想止步于仅仅知道: ① Android中,Kotlin协程用于解决:处理耗时任务 和 保证主线程安全;② 利用Kotlin协程,可以用看起来:同步 的方式编写 异步 代码;③ 基础的API调用;

6、并发 & 并行


上面提到一个名词 并发 (Concurrency),指的是:


同一时刻只有一条指令执行,但多个进程指令被快速地 轮换执行,使得在宏观上有同时执行的效果,微观上并不是同时执行,只是把CPU时间分成若干段,使得多个进程快速交替地执行,存在于单核或多核CPU系统中。


而另一个容易混淆的名词 并行 (Parallel) 则是:


同一时刻,有多条指令在多个处理器上同时执行,从微观和宏观上看,都是一起执行的,存在于多核CPU系统中。


7、协作式 & 抢夺式


单核CPU,同一时刻只有一个进程在执行,这么多进程,CPU的时间片该如何分配呢?

协作式多任务


早期的操作系统采用的就是协作时多任务,即:


由进程主动让出执行权,如当前进程需等待IO操作,主动让出CPU,由系统调度下一个进程。


每个进程都循规蹈矩,该让出CPU就让出CPU,是挺和谐的,但也存在一个隐患:


单个进程可以完全霸占CPU


计算机中的进程良莠不齐,先不说那种居心叵测的进程了,如果是健壮性比较差的进程,运行中途发生了死循环、死锁等,会导致整个系统陷入瘫痪!在这种鱼龙混杂的大环境下,把执行权托付给进程自身,肯定是不符合基础国情,由操作系统扛大旗的 抢占式多任务 横空出世~


抢占式多任务


由操作系统决定执行权,操作系统具有从任何一个进程取走控制权和使另一个进程获得控制权的能力。


系统公平合理地为每个进程分配时间片,进程用完就休眠,甚至时间片没用完,但有更紧急的事件要优先执行,也会强制让进程休眠。有了进程设计的经验,线程也做成了抢占式多任务,但也带来了新的——线程安全问题


8、线程安全问题


进程在执行过程中拥有独立的内存单元,而多个线程共享这个内存,可能存在这样一种情况:


假设有一个变量a = 10,它可以被线程t1和t2共享访问,两个线程都会对i值进行写入,假设在单核CPU上运行此程序,系统需要给两个线程都分配CPU时间片:


  • 1.t1从内存中读取了a的值为10,它把a的值+1,准备把11这个新值写入内存中,此时时间片耗尽;


  • 2.系统执行了线程调度,t1的执行现场被保存,t2获得执行,它也去读a的值,此时a的值仍为10,+1,然后把11写入内存中;


  • 3.t1再次被调度,此时它也把11写入内存中。


程序的执行结果和我们的预期不符,a的值应该为12而不是11,这就是线程调度不可预测性引起的 线程同步安全问题


解决方法


系列化访问临界资源,同一时刻,只能有一个线程访问临界资源,也称 同步互斥访问,通常的操作就是 加锁(同步锁),当线程访问临界资源时需要获得这个锁,其他线程无法访问,只能 等待(堵塞),等这个线程使用完释放锁,供其他线程继续访问。


前置概念相关的东西就说这么多,相信会对你接下来学习Kotlin协程大有裨益。


0x2、单线程的Android GUI系统


是的,Android GUI 被设计成单线程了,你可能会问:为啥不采用性能更高的多线程?


答:如果设计成多线程,多个线程同时对一个UI控件进行更新,容易发生 线程同步安全问题;最简单的解决方式:加锁,但这意味着更多的耗时和UI更新效率的降低,而且还有死锁等诸多问题要解决;多线程模型带来的复杂度成本,远远超出它能提供的性能优势成本。这也是大部分GUI系统都是单线程模型的原因。


Android要求:在主线程(UI线程)更新UI,注意是 → 要求建议,不是规定,规定底线是:


只有创建这个view的线程才能操作这个view


所以,你在子线程中更新子线程创建的UI也是可以的,不过不建议这么做,建议:


在子线程中完成耗时操作,然后通过Handler发送消息,通知UI线程更新UI。


Tips:关于Handler更多的内容可移步至:《换个姿势,带着问题看Handler》


接着说下,Android异步更新UI的写法都有哪些~


1、Handler


主线程中实例化一个Handler对象,在子线程需要更新UI的地方,通过Handler对象的post(runnable)或其他函数,往主线程的消息队列发送消息,等待调度器调度,分发给对应的Handler完成UI更新,写法示例如下:



利用 lambda表达式 + Kotlin语法糖thread { } 可对上述代码进行简化:



还有另外一种常见的写法:自定义一个静态内部类Handler,把UI更新操作统一放到这里,根据msg.what进行区分。


2、AsyncTask


AsyncTask是Android提供的一个轻量级的用于处理异步任务的类(封装Handler+Thread),使用代码示例如下:



相比起手写Handler简单了一些,只需要继承AsyncTask,然后就是填空题(按需重写函数):


  • onPreExecute():异步操作开始,可以做一些UI的初始化操作;


  • doInBackground():执行异步操作,可调用publishProgress()触发onProgressUpdate()进度更新;


  • onProgressUpdate():根据进度更新UI;


  • onPostExecute():异步操作完成,更新UI;


但也存在以下局限性:


① AsyncTask类需在主线程中加载;


② AsyncTask对象需在主线程中创建;


③ execute()必须在主线程中调用,且一个AsyncTask对象只能调用一次此方法;


④ 需要为每一种任务类型创建一个特定子类,同时为了访问UI方便,经常定义为Activity的内部类,耦合严重。


可以通过 函数转换为回调的方式 来解耦,抽取后的自定义AsyncTask类如下:



调用也很简单,按需重写对应函数即可:



解耦后灵活多了,外部调用逻辑内部异步逻辑 的分离开来了,但依旧存在问题,如异常处理、任务取消等。


相关文章
|
7月前
|
Java 数据库 Android开发
【专栏】Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
174 5
|
7月前
|
传感器 Android开发 开发者
构建高效Android应用:Kotlin的协程与Flow
【4月更文挑战第26天】随着移动应用开发的不断进步,开发者寻求更简洁高效的编码方式以应对复杂多变的业务需求。在众多技术方案中,Kotlin语言凭借其简洁性和强大的功能库逐渐成为Android开发的主流选择。特别是Kotlin的协程和Flow这两个特性,它们为处理异步任务和数据流提供了强大而灵活的工具。本文将深入探讨如何通过Kotlin协程和Flow来优化Android应用性能,实现更加流畅的用户体验,并展示在实际开发中的应用实例。
|
7月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin与协程的完美融合
【2月更文挑战第25天】 在移动开发领域,性能优化和应用响应性的提升是永恒的追求。随着Android Jetpack组件库的不断丰富,Kotlin语言已经成为Android开发的首选。而Kotlin协程作为一种新的并发处理方案,它以轻量级线程的形式,为开发者提供了简洁高效的异步编程手段。本文将深入探讨Kotlin协程在Android应用中的实践运用,以及如何通过这种技术改善用户界面的流畅度和后台任务的处理能力,进而构建出更高效、更稳定的Android应用。
|
7月前
|
安全 Android开发 开发者
构建高效Android应用:Kotlin与协程的完美结合
【2月更文挑战第30天】在移动开发领域,性能优化和流畅的用户体验是关键。本文深入探讨了如何通过结合Kotlin语言和协程技术来提升Android应用的性能和响应能力。我们将分析Kotlin的优势,介绍协程的基本概念,并通过实际案例展示如何在应用中实现协程以简化异步编程,从而提供更加高效的解决方案。
|
4月前
|
Go 调度 开发者
[go 面试] 深入理解进程、线程和协程的概念及区别
[go 面试] 深入理解进程、线程和协程的概念及区别
|
6月前
|
分布式计算 JavaScript 前端开发
多线程、多进程、协程的概念、区别与联系
多线程、多进程、协程的概念、区别与联系
92 1
|
2月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
27 1
|
3月前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
61 0
|
4月前
|
调度 开发者 UED
Kotlin 中的协程是什么?
【8月更文挑战第31天】
258 0
|
6月前
|
存储 Java 调度
Android面试题之Kotlin 协程的挂起、执行和恢复过程
了解Kotlin协程的挂起、执行和恢复机制。挂起时,状态和上下文(局部变量、调用栈、调度器等)被保存;挂起点通过`Continuation`对象处理,释放线程控制权。当恢复条件满足,调度器重新分配线程,调用`resumeWith`恢复执行。关注公众号“AntDream”获取更多并发知识。
133 2