一个任务队列的轮询执行方案

374 阅读1分钟

轮询一般由以下部分组成:

  • 任务对象
  • 存储任务对象的数据结构
  • 死循环
  • 循环终止条件

下面的例子中,通过 Kotlin 协程实现了一个自动关闭的轮询任务:

abstract class PollingTask {

    private var finishCallback: (() -> Unit)? = null

    abstract fun run()

    fun realRun() {
        run()
        finishCallback?.invoke()
    }

    fun finishCallback(block: (() -> Unit)?) {
        this.finishCallback = block
    }
}

object Dispatcher {

    private var task: Task? = null

    private var queue: LinkedList<Task> = LinkedList()

    private var pollingJob: Job? = null

    private var isDoing: AtomicBoolean = AtomicBoolean(false)

    private var isPolling = false

    val handler = Handler(Looper.getMainLooper())

    fun dispatch(task: Task) {
        queue.add(task)
        if (!isPolling) {
            startPolling()
        }
    }

    private fun startPolling() {
        pollingJob = CoroutineScope(Dispatchers.IO).launch {
            loop()
        }
        isPolling = true
    }

    private fun stopPolling() {
        isPolling = false
        pollingJob?.cancel()
    }

    private suspend fun loop() {
        while (true) {
            delay(1000)
            // 当队列为空时,自动取消轮询
            if (queue.isEmpty()) {
                Log.i(this.javaClass.name, "正在取消轮询")
                stopPolling()
                return
            }
            // 当前存在任务正在执行,跳过
            if (isDoing.get()) {
                continue
            }
            Log.i(this.javaClass.name, "正在轮询,当前剩余: ${queue.size}")
            task = queue.pop()
            // 任务执行完成,更新状态
            task?.finishCallback {
                isDoing.set(false)
                task = null
            }
            Log.i(this.javaClass.name, "当前剩余: ${queue.size}")

            // 这里可以酌情考虑要不要使用 post
            handler.post {
                task?.realRun()
                isDoing.set(true)
            }
        }
    }
}