一、协程基础使用

1. 协程的三种创建方式

(1) launch - 启动后台作业
val job = CoroutineScope(Dispatchers.IO).launch {// 后台操作delay(1000)println("任务完成 ${Thread.currentThread().name}")// 输出:任务完成 DefaultDispatcher-worker-1
}
job.join() // 等待完成
(2) async - 启动带结果作业
val deferred = CoroutineScope(Dispatchers.Default).async {delay(500)"计算结果"
}// 获取结果(会挂起协程)
val result = deferred.await()
println(result) // 输出:计算结果
(3) runBlocking - 阻塞线程启动
runBlocking {launch {delay(100)println("内部协程")}println("外部协程")
}
// 输出:
// 外部协程
// 内部协程

2. 调度器选择(四种核心类型)

调度器用途示例
Dispatchers.MainUI线程操作textView.text = "更新"
Dispatchers.IO网络/文件IORetrofit API调用
Dispatchers.DefaultCPU密集型计算复杂算法、数据处理
Dispatchers.Unconfined特殊场景不限制线程,慎用
CoroutineScope(Dispatchers.Main).launch {val data = withContext(Dispatchers.IO) { // 切换到IO线程fetchFromNetwork() // 网络请求}updateUI(data) // 回到主线程更新UI
}

3. 结构化并发(生命周期管理)

class MyActivity : AppCompatActivity() {// 绑定Activity生命周期private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)override fun onCreate() {scope.launch {loadData()}}override fun onDestroy() {scope.cancel() // 取消所有协程}suspend fun loadData() {// ...}
}

二、协程间通信

1. Channel - 点对点通信

(1) 基础使用
val channel = Channel<Int>()// 生产者
launch {repeat(5) {channel.send(it)delay(100)}channel.close()
}// 消费者
launch {for (value in channel) {println("收到: $value")}
}
// 输出: 收到: 0, 1, 2, 3, 4
(2) Channel类型对比
类型特性适用场景
RENDEZVOUS无缓冲(默认)严格同步
BUFFERED固定大小缓冲允许生产者领先
CONFLATED保留最新值状态更新
UNLIMITED无限缓冲大批量数据
// 创建不同类型Channel
val rendezvous = Channel<Int>() // 无缓冲
val buffered = Channel<Int>(10) // 缓冲区大小10
val conflated = Channel<Int>(Channel.CONFLATED) // 只保留最新

2. Flow - 异步数据流

(1) 冷流 vs 热流
特性Cold FlowHot Flow (SharedFlow)
启动收集时启动独立于收集者
数据每次收集重新发射共享数据流
示例数据库查询实时位置更新
(2) Flow基本使用
fun dataFlow(): Flow<Int> = flow {repeat(5) {delay(100)emit(it) // 发射数据}
}// 收集数据
CoroutineScope(Dispatchers.Main).launch {dataFlow().filter { it % 2 == 0 } // 过滤偶数.map { it * 2 } // 转换.collect { value -> // 收集println("值: $value")}
}
// 输出: 值: 0, 值: 4, 值: 8

3. SharedFlow & StateFlow - 状态管理

(1) SharedFlow - 事件广播
// 创建共享流(带重播1个事件)
val sharedFlow = MutableSharedFlow<Event>(replay = 1)// 发送事件
launch {sharedFlow.emit(Event.UPDATE)
}// 多个接收者
repeat(3) { i ->launch {sharedFlow.collect { event ->println("接收者$i: $event")}}
}
(2) StateFlow - 状态容器
// 创建状态容器(初始值0)
val stateFlow = MutableStateFlow(0)// 更新状态
launch {repeat(10) {delay(200)stateFlow.value = it}
}// 监听状态变化
launch {stateFlow.collect { state ->println("当前状态: $state")}
}
// 输出: 当前状态: 0,1,2,...,9

4. Select - 多路复用

val chan1 = Channel<String>()
val chan2 = Channel<String>()launch { delay(50); chan1.send("A") }
launch { delay(30); chan2.send("B") }// 选择最先到达的消息
val result = select<String> {chan1.onReceive { it }chan2.onReceive { it }
}println("结果: $result") // 输出: 结果: B

三、常见问题与答案

问题1:launch和async有什么区别?

标准回答:

  • launch 启动不需要返回结果的作业,返回Job对象用于控制生命周期

  • async 启动需要返回结果的作业,返回Deferred对象,通过await()获取结果

  • async 通常用于并行任务,launch用于后台执行

问题2:Channel和Flow有什么区别?

对比回答:

特性ChannelFlow
数据模式点对点单次消费流式多处理
冷热类型热数据通道默认为冷流
使用场景生产者-消费者数据处理管道
背压处理需手动控制内置操作符

问题3:StateFlow和LiveData如何选择?

  • 选择StateFlow

    • 纯Kotlin项目

    • 需要复杂数据转换

    • 需要协程集成

  • 选择LiveData

    • 现有Java代码库

    • 简单UI状态管理

    • 需要生命周期感知

问题4:如何在协程中处理异常?

最佳实践:

// 方式1:try-catch
launch {try {riskyOperation()} catch (e: Exception) {handleError(e)}
}// 方式2:CoroutineExceptionHandler
val handler = CoroutineExceptionHandler { _, e ->println("捕获异常: $e")
}CoroutineScope(Dispatchers.IO + handler).launch {throw RuntimeException("测试异常")
}

四、协程通信模式选择指南

场景推荐方案代码示例
UI状态管理StateFlowMutableStateFlow(initial)
全局事件通知SharedFlowMutableSharedFlow(replay=1)
一次性数据传递ChannelChannel<T>()
复杂数据处理Flowflow { emit(data) }
多源优先响应Selectselect { chan1.onReceive }
父子协程通信直接访问变量parentVar = value

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

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

相关文章

Ubuntu服务器(公网)- Ubuntu客户端(内网)的FRP内网穿透配置教程

以下是为Ubuntu服务器&#xff08;公网&#xff09;- Ubuntu客户端&#xff08;内网&#xff09;的FRP内网穿透配置教程&#xff0c;基于最新版本&#xff08;2025年6月&#xff0c;使用frp_0.61.1_linux_amd64&#xff09;整理&#xff1a; 一、服务端配置&#xff08;公网Ubu…

什么是哈希函数(SHA-256)

SHA-256 是区块链系统中最核心的加密基础之一&#xff0c;尤其是在比特币、以太坊、文件存证等场景中扮演“指纹识别器”的角色。下面是对它的详细讲解&#xff0c;包括原理、特点、用途和代码示例。 &#x1f4cc; 一、什么是 SHA-256&#xff1f; SHA-256 是一种密码学哈希函…

大模型的“Tomcat”:一文读懂AI推理引擎(Inference Engine)

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

《从0到1:C/C++音视频开发自学完全指南》

从0到1&#xff1a;C/C音视频开发自学完全指南 一、开篇&#xff1a;为什么选择C/C切入音视频开发&#xff1f; 当你刷着抖音短视频、参加腾讯会议、观看B站直播时&#xff0c;背后都是音视频技术在支撑。根据艾瑞咨询数据&#xff0c;2024年中国音视频相关产业规模已突破5000…

微信小程序之单行溢出隐藏和双行溢出隐藏

首先&#xff0c;我们做个text&#xff0c;加入了一个长文本&#xff0c;就像下面那样&#xff1a; wxml : <view class"container"><text>刘德华&#xff08;Andy Lau&#xff09;&#xff0c;1961年9月27日出生于中国香港&#xff0c;华语影视男演员、…

PHP安装使用教程

一、PHP 简介 PHP&#xff08;Hypertext Preprocessor&#xff09;是一种广泛应用的开源服务器端脚本语言&#xff0c;尤其适用于 Web 开发&#xff0c;可嵌入 HTML 中使用。其运行速度快、易学易用&#xff0c;支持多种数据库和平台。 二、PHP 安装教程 2.1 支持平台 PHP 支…

ThreadLocal、InheritableThreadLocal与TransmittableThreadLocal深度解析

文章目录 一、概念说明1、ThreadLocal2、InheritableThreadLocal3、TransmittableThreadLocal 二、使用场景1、ThreadLocal2、InheritableThreadLocal3、TransmittableThreadLocal 三、存在的问题1、ThreadLocal2、InheritableThreadLocal3、TransmittableThreadLocal 四、示例…

ERP系统Bug记录

2025.06.30 2025/06/30-10:51:02 [http-nio-9999-exec-3] com.yxx.jsh.erp.service.LogService - 异常码[300],异常提示[数据查询异常],异常[{}] java.lang.NullPointerException: nullat com.yxx.jsh.erp.base.TableSupport.getBuildPageRequest(TableSupport.java:46)at com…

C# Avalonia 的 Source Generators 用处

C# Avalonia 的 Source Generators 用处 文章目录 **1. 自动生成 MVVM 绑定代码****2. 强类型 XAML 数据绑定****3. 自动注册视图&#xff08;View&#xff09;与视图模型&#xff08;ViewModel&#xff09;****4. 资源文件与本地化的强类型访问****5. 路由事件与命令的自动化处…

stm32之测量占空比

#include "tim4.h"void TIM4_Init(void) {// 开启时钟RCC->APB1ENR | RCC_APB1ENR_TIM4EN;RCC->APB2ENR | RCC_APB2ENR_IOPBEN; // 使用 TIM4 的 GPIOB 时钟// 配置 PB6 为浮空输入 CNF 01 MODE 00GPIOB->CRL & ~GPIO_CRL_MODE6;GPIOB->CRL & ~G…

工厂模式 - Flutter中的UI组件工厂,按需生产各种“产品

想要动态创建不同风格的按钮&#xff1f;想一键切换整个主题&#xff1f;工厂模式就是你的"生产流水线"&#xff01; 想象一下这个场景&#xff1a; 你决定扩大奶茶店业务&#xff0c;推出两个品牌系列&#xff1a; 经典系列&#xff1a;传统珍珠奶茶&#xff0c;红…

基于 SpringBoot+Vue.js+ElementUI 的 Cosplay 论坛设计与实现7000字论文

基于 SpringBootVue.jsElementUI 的 Cosplay 论坛设计与实现 摘要 本论文设计并实现了一个基于 SpringBoot、Vue.js 和 ElementUI 的 Cosplay 论坛平台。该平台旨在为 Cosplay 爱好者提供一个集作品展示、交流互动、活动组织于一体的综合性社区。论文首先分析了 Cosplay 论坛…

超标量处理器11-Alpha21264 处理器

1. 简介 21264处理器是一款4-way&#xff0c;乱序执行的超标量处理器&#xff0c;采用0.35um的CMOS工艺&#xff0c;工作电压是2.2V, 工作频率是466-667MHz; 处理器能支持60条指令&#xff0c;也即ROB的深度是60; Load/Store指令也采取乱序执行, 总共7级流水。I-CACHE和D-CACH…

Spring 中 Bean 的生命周期

一、什么是 Bean 生命周期&#xff1f; Spring 中的 Bean 生命周期是指一个 Bean 从 被容器创建到 最终销毁 所经历的一系列过程。 它体现了 Spring IOC 容器在管理 Bean 实例时所执行的各个钩子流程&#xff0c;包括初始化、依赖注入、增强处理、销毁等多个环节。 二、Bean 生…

C++ 中 std::string 与 QString 的深度剖析

在 C 编程领域&#xff0c;std::string 和 QString 是两种广泛应用的字符串类型&#xff0c;它们在设计理念、功能特性以及适用场景上都呈现出鲜明的特点。本文将从多个维度对这两种字符串类型进行深度剖析&#xff0c;并详细阐述它们之间的相互转化方法。 std::string 是 C 标…

不止于“修补”:我如何用Adobe AI重塑设计与视频叙事流程

最近我深度体验了一把来自英国Parvis School of Economics and Music的Adobe正版教育订阅&#xff0c;在把玩PhotoShop、Premiere Pro这些“老伙计”的新功能时&#xff0c;的确挖到了一些宝藏&#xff0c;觉得非常有必要与大家说道说道。首先得聊聊这个订阅给我的直观感受&…

重头开始学ROS(5)---阿克曼底盘的URDF建模与Gazebo控制(使用Xacro优化)

阿克曼底盘的URDF建模与Gazebo控制&#xff08;使用Xacro优化&#xff09; 阿克曼底盘建模 建模 我们使用后轮驱动&#xff0c;前轮转向的阿克曼底盘模型。 那么对于后轮只需进行正常的continous joint连接即可 对于前轮&#xff0c;有两个自由度&#xff0c;旋转和转向&…

RabbitMq中启用NIO

✅ 所属类 com.rabbitmq.client.ConnectionFactory&#x1f9e0; 使用背景 RabbitMQ Java 客户端默认使用传统的 阻塞 I/O (java.net.Socket) 实现。如果你希望&#xff1a; 更好地控制 线程数获得更好的 并发性能降低 每个连接的线程占用在高并发连接或消费者数量较多的系统…

[Dify]-基础篇2- 如何注册并快速上手 Dify 平台

在生成式 AI 应用开发新时代,如何快速搭建一个高效、可维护、易上线的 AI 工具,是每位开发者关注的核心。Dify,正是为此而生的一站式平台。本篇将以新手视角,带你从注册账号、配置环境,到构建应用、部署上线,手把手完成你的第一个 AI 项目。 注册并设置工作环境 1. 账号…

Java面试宝典:基础七

153. 如何实现对象克隆? 答: 对象克隆有两种主要方式: 浅克隆:实现Cloneable接口并重写Object.clone() class Person implements Cloneable {String name;Car car; // 引用类型@Override