Android面试题之Kotlin协程到底是什么?它是线程吗?

简介: 本文探讨了协程与线程的区别,指出协程并非线程,而是轻量级的线程替代。协程轻量体现在它们共享调用栈,内存占用少,仅需几个KB。协程切换发生在用户态,避免了昂贵的内核态切换。在Kotlin中,协程通过Continuation对象实现上下文保存,允许高效并发执行,而不会像线程那样消耗大量资源。通过`runBlocking`和`launch`示例展示了协程的非阻塞挂起特性。总结来说,协程的轻量主要源于内存占用少、切换开销低和高并发能力。

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

协程是什么?

协程是线程吗?是线程池的线程?是轻量级的线程?

实际上,可以非常肯定的说,协程不是线程!

我们反过来想,如果协程是线程,那么咱们怎么让一个线程挂起呢?

那既然协程不是线程,那又为什么常说协程是轻量级的线程呢?协程轻在哪呢?

"轻量级"的线程

Kotlin中的协程经常被称为“轻量级线程”,这是相对于传统的线程模型而言的。为了更好地理解这一点,我们需要从内存占用、任务切换、JVM内存模型等多方面进行剖析。

1. 轻量级的原因

1.1 内存占用

  • 线程: 每个线程在创建时分配一定数量的栈内存(默认大约1MB)。如果系统启动大量线程,则会消耗大量内存,可能导致系统资源枯竭。
  • 协程: 协程是运行在现有线程中的,它们不需要单独的栈内存,而是共享调用栈。这样协程仅需要少量内存开销,通常每个协程只占用几个KB。这使得同一线程可以管理和运行大量协程,不受传统线程数量限制。

1.2 任务切换

  • 线程切换: 线程切换由操作系统管理,涉及到用户态和内核态之间的切换,代价较高,需要保存和恢复CPU寄存器、程序计数器、内存栈等。
  • 协程切换: 协程切换在用户态完成,不涉及内核态切换,只是切换函数的上下文,代价相对低很多。

2. 内存模型

2.1 线程内存模型

在JVM中,每个线程都有自己独立的线程栈,每个栈帧包含局部变量、操作数栈和相关信息。当线程被挂起时,所有这些信息必须保存并在重新调度时恢复。

2.2 协程内存模型

协程的栈帧通常是堆上的对象,当协程挂起时,不需要切换线程,只是函数调用的上下文发生变化,把协程状态保存到堆中。这种模型使得内存利用更加高效和灵活。

2.3 协程堆栈帧

协程在挂起时,会将当前的堆栈帧转换为对象并存储在堆中。这个对象包含了所有当前帧的局部变量、挂起点以及其他必要信息。恢复时,这个对象重新转换为堆栈帧并继续执行。

2.4 Continuation

Kotlin中的挂起函数实质上会被编译器转换成带有回调的 Continuation 对象。该对象包含两个主要部分:

  • 上下文(Continuation Context):绑定的执行环境。
  • 恢复逻辑(Resume Logic):保存和处理挂起点的逻辑。
interface Continuation<in T> {
    val context: CoroutineContext
    fun resumeWith(result: Result<T>)
}

3. 执行机制

3.1 线程

线程由操作系统调度,执行时获得CPU时间片,可能被抢占。这一过程完全由操作系统管理,且每次线程切换都会导致上下文切换,引入显著的开销。

3.2 协程

协程仅占用一个线程的部分时间,是由协程库(例如 kotlinx.coroutines)管理。一个线程可以执行多个协程,只要它们异步工作并时常挂起和恢复。这大大减少了切换开销,改善性能。

4. 协程例子

import kotlinx.coroutines.*

fun main() = runBlocking {
    repeat(100_000) {
        launch {
            delay(1000L)
            println("Coroutine $it is done")
        }
    }
}

在这个例子中,启动了10万协程,但内存占用远远小于10万个线程,且切换效率高。这是因为:

  • 非阻塞挂起: delay 使得协程挂起,但不阻塞线程,使得同一线程可以继续处理其他协程。
  • 上下文保存和恢复: 协程的上下文切换只需要保存和恢复堆上的对象状态,代价低。

由于协程不阻塞线程,上面的例子中,日志几乎是同时打印的

总结

Kotlin 协程的,主要原因包括:

  1. 内存占用更少:协程不需要独立的栈内存,而是共享调用栈。
  2. 低切换开销:协程切换在用户态完成,无需与操作系统交互,开销小。
  3. 高并发模型:在同一线程上可以高效地运行大量协程,不受传统线程创建管理的限制。

欢迎关注我的公众号AntDream查看更多精彩文章!

目录
相关文章
|
2月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
3月前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
4月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
90 4
|
5月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
177 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
4月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
68 1
|
5月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
178 5
|
5月前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
5月前
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
178 1
|
存储 缓存 Java
Android--面试中遇到的问题总结(一)
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/56479430 一、handl...
1348 0
|
Android开发 容器 缓存
Android--面试中遇到的问题总结(二)
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/56480392 一、开发中都...
1256 0