kotlin 线程间通信 channel sharedflow

在Kotlin中,可以使用Channel或SharedFlow来实现多个线程之间的消息传递,同时保证只有一个数据对象被传递。以下是两种方法的演示:

方法1:使用 Channel

Channel 是一个轻量级的通信原语,类似于队列。它可以用于在多个线程之间传递信息。

代码演示
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel

fun main() = runBlocking {
  val channel = Channel<String>(Channel.CONFLATED) // 创建一个Conflated channel,确保只有一个数据对象

  // 启动生产者协程
  val producer = launch {
    val data = "Hello from producer"
    println("Producer sending: $data")
    channel.send(data)
  }

  // 启动消费者协程
  val consumer = launch {
    val receivedData = channel.receive()
    println("Consumer received: $receivedData")
  }

  // 等待生产者和消费者完成
  producer.join()
  consumer.join()
}
解释:
  • Channel.CONFLATED:它表示Channel只会保留最新的值,旧的值将会被丢弃,从而保证在同一时间只有一个数据对象在Channel中。
运行结果:

生产者发送数据后,消费者接收数据,输出结果会是:

Producer sending: Hello from producer
Consumer received: Hello from producer

方法2:使用 SharedFlow

SharedFlow 是一种热流(Hot Flow),可以让多个消费者接收同一个数据对象。

代码演示
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect

fun main() = runBlocking {
  val sharedFlow = MutableSharedFlow<String>(replay = 1) // replay参数为1,表示只保留最后一个值

  // 启动生产者协程
  val producer = launch {
    val data = "Hello from producer"
    println("Producer emitting: $data")
    sharedFlow.emit(data)
  }

  // 启动消费者协程
  val consumer1 = launch {
    sharedFlow.collect { data ->
      println("Consumer1 received: $data")
    }
  }

  val consumer2 = launch {
    sharedFlow.collect { data ->
      println("Consumer2 received: $data")
    }
  }

  // 等待生产者和消费者完成
  producer.join()
  consumer1.cancel()
  consumer2.cancel()
}
解释:
  • MutableSharedFlow(replay = 1):这个设置意味着SharedFlow只会保留最后一次发射的数据,这样可以保证多个消费者都接收到同样的数据对象。
运行结果:

生产者发射数据后,两个消费者都能接收到相同的数据对象,输出结果会是:

Producer emitting: Hello from producer
Consumer1 received: Hello from producer
Consumer2 received: Hello from producer

结论

  • Channel:适用于点对点的消息传递。使用Channel.CONFLATED可以保证同一时间只有一个数据对象在传递。
  • SharedFlow:适用于一对多的消息传递,多个消费者可以接收到同样的数据对象。

Hotkeys:

  • W: 是的,继续
  • A: 提供另一种方法
  • S: 解释代码
  • T: 编写测试用例列表
    在Kotlin中,使用Channel进行通信时,默认情况下,每个消息在通道中只会被消费一次。也就是说,当一个协程从Channel中接收到一个消息后,该消息就会从通道中移除,其他协程无法再接收到相同的消息。

示例代码说明 Channel 消息只被消费一次

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel

fun main() = runBlocking {
  val channel = Channel<String>() // 创建一个Channel

  // 启动生产者协程
  val producer = launch {
    val data = "Hello from producer"
    println("Producer sending: $data")
    channel.send(data)
  }

  // 启动第一个消费者协程
  val consumer1 = launch {
    val receivedData = channel.receive()
    println("Consumer1 received: $receivedData")
  }

  // 启动第二个消费者协程
  val consumer2 = launch {
    val receivedData = channel.receive()
    println("Consumer2 received: $receivedData")
  }

  // 等待生产者和消费者完成
  producer.join()
  consumer1.join()
  consumer2.join()
}
解释:
  • Channel:这里的Channel是一个普通的Channel,它的消息只能被一个消费者接收并处理。
  • 消费者:在这个示例中,第一个消费者接收到消息后,该消息就从通道中移除了,第二个消费者会等待新的消息而不是接收到相同的消息。
运行结果:
Producer sending: Hello from producer
Consumer1 received: Hello from producer

注意,只有Consumer1收到了消息,而Consumer2会无限等待,因为没有更多消息发送到Channel中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值