Kotlin协程flow缓冲buffer任务流,批次任务中选取优先级最高任务最先运行(八)
在 https://blog.csdn.net/zhangphil/article/details/158844549 基础上改进,增加Listener接口,监听request的状态。
实现基于Kotlin协程的优先级任务调度系统。通过PriorityBlockingQueue实现任务优先级排序,使用Channel和Flow进行任务流缓冲处理。系统支持任务取消机制,并新增Listener接口监听任务状态变化(开始/取消)。核心类包括Loader(任务执行)、LoadRequest(任务请求)和LoadMgr(调度管理器)。测试案例显示,系统能正确按优先级执行任务,并在任务取消时触发回调。该方案适用于需要并发处理且需动态调整优先级的场景,如后台任务调度等。
Kotlin
import java.util.UUID
open class Loader {
companion object {
private const val TAG = "fly/Loader"
}
private var id: Any? = UUID.randomUUID()
constructor() {
}
open fun setId(id: Any?) {
this.id = id
}
open fun getId(): Any? {
return id
}
open fun doInBackground(): Result<Any>? {
return null
}
open fun deliveryResult(result: Result<Any>?) {
}
override fun equals(other: Any?): Boolean {
return id == (other as Loader).id
}
}
Kotlin
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.newFixedThreadPoolContext
import java.util.concurrent.PriorityBlockingQueue
class LoadMgr {
companion object {
private const val TAG = "fly/LoadMgr"
val INSTANCE = LoadMgr()
val THREAD_POOL = newFixedThreadPoolContext(nThreads = 4, name = "线程")
}
private val mChannel = Channel<LoadRequest>()
private val bufferCapacity = 10
private val initialCapacity = 50
private val mPriorityBlockingQueue = PriorityBlockingQueue(
initialCapacity,
Comparator<LoadRequest> { o1, o2 -> o2.getPriority()!!.ordinal - o1.getPriority()!!.ordinal })
private constructor() {
println("$TAG constructor")
}
fun startup() {
//接收任务
CoroutineScope(THREAD_POOL).async {
println("$TAG Channel start... ${Thread.currentThread().name}")
mChannel.receiveAsFlow()
.onEach { it -> //生产者
//println("$TAG onEach-$it ${Thread.currentThread().name}")
}.buffer(bufferCapacity)
.collect { it -> //消费者
//collect, 这里相当于通过缓冲后匀速发射过来的触发器(trigger)。
//收集到的值在此并不重要,这里,只是把它作为触发信号。
//println("$TAG collect-$it ${Thread.currentThread().name}")
trigger()
}
}
}
private fun trigger() {
val loadRequest = mPriorityBlockingQueue.poll()
println("$TAG 当前最大优先级任务:${loadRequest} ${Thread.currentThread().name}")
loadRequest?.let {
CoroutineScope(THREAD_POOL).async {
val result = if (it.isCancelled()) {
it.getListener()?.onCancel(it)
println("$TAG id=${loadRequest.getId()} isCancelled=${it.isCancelled()}")
return@async
} else {
it.getListener()?.onStart(it)
it.getLoader()?.doInBackground()
}
println("$TAG id=${loadRequest} doInBackground完成 isCancelled=${loadRequest.isCancelled()} ${Thread.currentThread().name}")
if (it.isCancelled()) {
it.getListener()?.onCancel(it)
} else {
println("$TAG deliveryResult loadRequest=${loadRequest} ${Thread.currentThread().name}")
it.getLoader()?.deliveryResult(result)
}
}
}
}
fun enqueue(taskInfo: LoadRequest) {
CoroutineScope(THREAD_POOL).async {
mPriorityBlockingQueue.add(taskInfo)
mChannel.send(taskInfo)
}
}
fun destroy() {
mChannel.cancel()
mChannel.close()
}
}
Kotlin
import java.util.UUID
open class LoadRequest {
private var id: Any? = null
private var tag: Any? = null
private var loader: Loader? = null
private var priority: Priority? = null
private var listener: Listener? = null
private var isCancelled = false
private constructor() {
}
fun getId(): Any? {
return id
}
fun getTag(): Any? {
return tag
}
fun getLoader(): Loader? {
return loader
}
fun getListener(): Listener? {
return listener
}
fun getPriority(): Priority? {
return priority
}
open fun cancel() {
isCancelled = true
}
open fun isCancelled(): Boolean {
return isCancelled
}
override fun equals(other: Any?): Boolean {
return id == (other as LoadRequest).id
}
override fun toString(): String {
return "LoadRequest(id=$id, tag=$tag, priority=$priority, isCancelled=$isCancelled)"
}
interface Listener {
fun onStart(request: LoadRequest?) {}
fun onCancel(request: LoadRequest?) {}
fun onError() {}
fun onSuccess() {}
}
class Builder {
private var id: Any? = UUID.randomUUID()
private var tag: Any? = null
private var loader: Loader? = null
private var priority: Priority? = Priority.NORMAL
private var listener: Listener? = null
constructor() {
}
fun id(id: Any): Builder {
this.id = id
return this
}
fun tag(tag: Any): Builder {
this.tag = tag
return this
}
fun loader(loader: Loader): Builder {
this.loader = loader
return this
}
fun listener(listener: Listener): Builder {
this.listener = listener
return this
}
fun priority(priority: Priority): Builder {
this.priority = priority
return this
}
fun build(): LoadRequest {
val request = LoadRequest()
request.id = id
request.tag = tag
request.loader = loader
request.priority = priority
request.listener = listener
return request
}
}
}
Kotlin
import kotlin.random.Random
fun main() {
val TAG = "fly/main"
LoadMgr.INSTANCE.startup()
val requests = ArrayList<LoadRequest>()
//源源不断的密集发送加载任务。
repeat(30) { idx ->
val loader = MyLoader()
loader.setId(idx)
val p = Priority.entries.toTypedArray().random()
val request = LoadRequest.Builder()
.id(idx)
.priority(p)
.listener(object : LoadRequest.Listener {
override fun onCancel(request: LoadRequest?) {
println("$TAG id=${request?.getId()} Listener cancelled")
}
})
.loader(loader)
.build()
requests.add(request)
LoadMgr.INSTANCE.enqueue(request)
}
println("$TAG enqueue 全部发送完成")
//模拟在众多并发任务启动后,由于某些情况,加载任务突然需要取消。
requests.shuffle().run {
requests.forEachIndexed { _, request ->
Thread.sleep(100)
if (Random.nextBoolean()) {
request.cancel()
println("$TAG id=${request.getId()} cancel()")
}
}
}
Thread.sleep(999999)
println("$TAG sleep结束")
LoadMgr.INSTANCE.destroy()
}
Kotlin
class MyLoader : Loader() {
companion object {
const val TAG = "fly/MyLoader"
}
override fun doInBackground(): Result<Any>? {
println("$TAG id=${getId()} doInBackground开始 ${Thread.currentThread().name}")
//假设耗时操作
Thread.sleep(2000)
println("$TAG id=${getId()} doInBackground完成 ${Thread.currentThread().name}")
val result = Result.success("hello, result id=${getId()}")
return result
}
// 不要寄希望于doInBackground里面直接返回结果,因为在并发任务环境下,如果doInBackground已开始运行,框架就无法取消它的运行,即便之后通过总控开关取消这条请求。
// 因此,在deliveryResult等待任务正常加载(没有被取消)后返回的结果,才能保证并发任务逻辑上的正常。
override fun deliveryResult(result: Result<Any>?) {
println("$TAG id=${getId()} deliveryResult ${result?.getOrNull()} ${Thread.currentThread().name}")
}
}
Kotlin
enum class Priority {
LOW,
NORMAL,
HIGH,
IMMEDIATELY
}
Kotlin
open class SimpleLoader : Loader() {
open fun worker() {
}
final override fun doInBackground(): Result<Any>? {
worker()
return null
}
}
运行输出:
fly/LoadMgr constructor
fly/LoadMgr Channel start... 线程-1
fly/main enqueue 全部发送完成
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=2, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=15, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=20, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-3
fly/MyLoader id=2 doInBackground开始 线程-2
fly/MyLoader id=15 doInBackground开始 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=26, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-3
fly/MyLoader id=20 doInBackground开始 线程-4
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=28, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=29, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=9, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=8, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=23, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=4, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=27, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=14, tag=null, priority=HIGH, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=7, tag=null, priority=NORMAL, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=18, tag=null, priority=NORMAL, isCancelled=false) 线程-3
fly/MyLoader id=26 doInBackground开始 线程-3
fly/main id=0 cancel()
fly/main id=23 cancel()
fly/main id=2 cancel()
fly/main id=22 cancel()
fly/main id=5 cancel()
fly/main id=12 cancel()
fly/main id=17 cancel()
fly/main id=24 cancel()
fly/MyLoader id=2 doInBackground完成 线程-2
fly/MyLoader id=26 doInBackground完成 线程-3
fly/MyLoader id=15 doInBackground完成 线程-1
fly/MyLoader id=20 doInBackground完成 线程-4
fly/LoadMgr id=LoadRequest(id=26, tag=null, priority=IMMEDIATELY, isCancelled=false) doInBackground完成 isCancelled=false 线程-3
fly/LoadMgr id=LoadRequest(id=20, tag=null, priority=IMMEDIATELY, isCancelled=false) doInBackground完成 isCancelled=false 线程-4
fly/LoadMgr id=LoadRequest(id=15, tag=null, priority=IMMEDIATELY, isCancelled=false) doInBackground完成 isCancelled=false 线程-1
fly/LoadMgr id=LoadRequest(id=2, tag=null, priority=IMMEDIATELY, isCancelled=true) doInBackground完成 isCancelled=true 线程-2
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=26, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-3
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=20, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-4
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=15, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-1
fly/main id=2 Listener cancelled
fly/MyLoader id=28 doInBackground开始 线程-2
fly/MyLoader id=20 deliveryResult hello, result id=20 线程-4
fly/MyLoader id=26 deliveryResult hello, result id=26 线程-3
fly/MyLoader id=15 deliveryResult hello, result id=15 线程-1
fly/MyLoader id=9 doInBackground开始 线程-3
fly/MyLoader id=29 doInBackground开始 线程-4
fly/MyLoader id=8 doInBackground开始 线程-1
fly/main id=21 cancel()
fly/main id=15 cancel()
fly/main id=13 cancel()
fly/main id=4 cancel()
fly/main id=20 cancel()
fly/main id=9 cancel()
fly/main id=26 cancel()
fly/main id=14 cancel()
fly/MyLoader id=9 doInBackground完成 线程-3
fly/LoadMgr id=LoadRequest(id=9, tag=null, priority=HIGH, isCancelled=true) doInBackground完成 isCancelled=true 线程-3
fly/main id=9 Listener cancelled
fly/MyLoader id=29 doInBackground完成 线程-4
fly/MyLoader id=8 doInBackground完成 线程-1
fly/MyLoader id=28 doInBackground完成 线程-2
fly/LoadMgr id=LoadRequest(id=8, tag=null, priority=HIGH, isCancelled=false) doInBackground完成 isCancelled=false 线程-1
fly/LoadMgr id=LoadRequest(id=29, tag=null, priority=HIGH, isCancelled=false) doInBackground完成 isCancelled=false 线程-4
fly/main id=23 Listener cancelled
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=8, tag=null, priority=HIGH, isCancelled=false) 线程-1
fly/LoadMgr id=LoadRequest(id=28, tag=null, priority=IMMEDIATELY, isCancelled=false) doInBackground完成 isCancelled=false 线程-2
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=29, tag=null, priority=HIGH, isCancelled=false) 线程-4
fly/MyLoader id=8 deliveryResult hello, result id=8 线程-1
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=28, tag=null, priority=IMMEDIATELY, isCancelled=false) 线程-2
fly/MyLoader id=29 deliveryResult hello, result id=29 线程-4
fly/main id=4 Listener cancelled
fly/MyLoader id=28 deliveryResult hello, result id=28 线程-2
fly/MyLoader id=27 doInBackground开始 线程-4
fly/main id=14 Listener cancelled
fly/LoadMgr id=14 isCancelled=true
fly/LoadMgr id=23 isCancelled=true
fly/LoadMgr id=4 isCancelled=true
fly/MyLoader id=18 doInBackground开始 线程-3
fly/MyLoader id=7 doInBackground开始 线程-2
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=1, tag=null, priority=NORMAL, isCancelled=false) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=25, tag=null, priority=NORMAL, isCancelled=false) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=24, tag=null, priority=NORMAL, isCancelled=true) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=0, tag=null, priority=NORMAL, isCancelled=true) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=10, tag=null, priority=LOW, isCancelled=false) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=22, tag=null, priority=LOW, isCancelled=true) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=5, tag=null, priority=LOW, isCancelled=true) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=12, tag=null, priority=LOW, isCancelled=true) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=11, tag=null, priority=LOW, isCancelled=false) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=3, tag=null, priority=LOW, isCancelled=false) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=21, tag=null, priority=LOW, isCancelled=true) 线程-1
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=16, tag=null, priority=LOW, isCancelled=false) 线程-1
fly/MyLoader id=1 doInBackground开始 线程-1
fly/MyLoader id=27 doInBackground完成 线程-4
fly/LoadMgr id=LoadRequest(id=27, tag=null, priority=HIGH, isCancelled=false) doInBackground完成 isCancelled=false 线程-4
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=27, tag=null, priority=HIGH, isCancelled=false) 线程-4
fly/MyLoader id=27 deliveryResult hello, result id=27 线程-4
fly/MyLoader id=25 doInBackground开始 线程-4
fly/MyLoader id=18 doInBackground完成 线程-3
fly/MyLoader id=7 doInBackground完成 线程-2
fly/LoadMgr id=LoadRequest(id=18, tag=null, priority=NORMAL, isCancelled=false) doInBackground完成 isCancelled=false 线程-3
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=18, tag=null, priority=NORMAL, isCancelled=false) 线程-3
fly/LoadMgr id=LoadRequest(id=7, tag=null, priority=NORMAL, isCancelled=false) doInBackground完成 isCancelled=false 线程-2
fly/MyLoader id=18 deliveryResult hello, result id=18 线程-3
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=7, tag=null, priority=NORMAL, isCancelled=false) 线程-2
fly/MyLoader id=7 deliveryResult hello, result id=7 线程-2
fly/main id=24 Listener cancelled
fly/LoadMgr id=24 isCancelled=true
fly/main id=0 Listener cancelled
fly/MyLoader id=10 doInBackground开始 线程-3
fly/LoadMgr id=0 isCancelled=true
fly/main id=22 Listener cancelled
fly/LoadMgr id=22 isCancelled=true
fly/main id=5 Listener cancelled
fly/LoadMgr id=5 isCancelled=true
fly/main id=12 Listener cancelled
fly/LoadMgr id=12 isCancelled=true
fly/MyLoader id=11 doInBackground开始 线程-2
fly/MyLoader id=1 doInBackground完成 线程-1
fly/LoadMgr id=LoadRequest(id=1, tag=null, priority=NORMAL, isCancelled=false) doInBackground完成 isCancelled=false 线程-1
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=1, tag=null, priority=NORMAL, isCancelled=false) 线程-1
fly/MyLoader id=1 deliveryResult hello, result id=1 线程-1
fly/MyLoader id=3 doInBackground开始 线程-1
fly/MyLoader id=25 doInBackground完成 线程-4
fly/LoadMgr id=LoadRequest(id=25, tag=null, priority=NORMAL, isCancelled=false) doInBackground完成 isCancelled=false 线程-4
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=25, tag=null, priority=NORMAL, isCancelled=false) 线程-4
fly/MyLoader id=25 deliveryResult hello, result id=25 线程-4
fly/main id=21 Listener cancelled
fly/LoadMgr id=21 isCancelled=true
fly/MyLoader id=16 doInBackground开始 线程-4
fly/MyLoader id=10 doInBackground完成 线程-3
fly/LoadMgr id=LoadRequest(id=10, tag=null, priority=LOW, isCancelled=false) doInBackground完成 isCancelled=false 线程-3
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=10, tag=null, priority=LOW, isCancelled=false) 线程-3
fly/MyLoader id=10 deliveryResult hello, result id=10 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=13, tag=null, priority=LOW, isCancelled=true) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=19, tag=null, priority=LOW, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=6, tag=null, priority=LOW, isCancelled=false) 线程-3
fly/LoadMgr 当前最大优先级任务:LoadRequest(id=17, tag=null, priority=LOW, isCancelled=true) 线程-3
fly/main id=13 Listener cancelled
fly/LoadMgr id=13 isCancelled=true
fly/MyLoader id=19 doInBackground开始 线程-3
fly/MyLoader id=11 doInBackground完成 线程-2
fly/LoadMgr id=LoadRequest(id=11, tag=null, priority=LOW, isCancelled=false) doInBackground完成 isCancelled=false 线程-2
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=11, tag=null, priority=LOW, isCancelled=false) 线程-2
fly/MyLoader id=11 deliveryResult hello, result id=11 线程-2
fly/MyLoader id=6 doInBackground开始 线程-2
fly/MyLoader id=3 doInBackground完成 线程-1
fly/LoadMgr id=LoadRequest(id=3, tag=null, priority=LOW, isCancelled=false) doInBackground完成 isCancelled=false 线程-1
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=3, tag=null, priority=LOW, isCancelled=false) 线程-1
fly/MyLoader id=3 deliveryResult hello, result id=3 线程-1
fly/main id=17 Listener cancelled
fly/LoadMgr id=17 isCancelled=true
fly/MyLoader id=16 doInBackground完成 线程-4
fly/LoadMgr id=LoadRequest(id=16, tag=null, priority=LOW, isCancelled=false) doInBackground完成 isCancelled=false 线程-4
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=16, tag=null, priority=LOW, isCancelled=false) 线程-4
fly/MyLoader id=16 deliveryResult hello, result id=16 线程-4
fly/MyLoader id=6 doInBackground完成 线程-2
fly/LoadMgr id=LoadRequest(id=6, tag=null, priority=LOW, isCancelled=false) doInBackground完成 isCancelled=false 线程-2
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=6, tag=null, priority=LOW, isCancelled=false) 线程-2
fly/MyLoader id=6 deliveryResult hello, result id=6 线程-2
fly/MyLoader id=19 doInBackground完成 线程-3
fly/LoadMgr id=LoadRequest(id=19, tag=null, priority=LOW, isCancelled=false) doInBackground完成 isCancelled=false 线程-3
fly/LoadMgr deliveryResult loadRequest=LoadRequest(id=19, tag=null, priority=LOW, isCancelled=false) 线程-3
fly/MyLoader id=19 deliveryResult hello, result id=19 线程-3