You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何暂停与恢复IO任务?协程及非协程实现方案咨询

非协程方式实现可暂停/恢复的文件复制操作

要实现可暂停、恢复的文件复制IO任务,核心思路是分块执行文件传输,配合线程安全的状态标记和等待/唤醒机制,让IO线程能响应Main线程的控制指令。以下是具体实现方案:

1. 定义复制控制器(线程安全的状态管理)

先创建一个控制器类,统一管理复制任务的暂停、恢复状态及复制线程:

import java.nio.channels.FileChannel
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock

class FileCopyController {
    private val lock = ReentrantLock()
    private val pauseCondition: Condition = lock.newCondition()
    private val isPaused = AtomicBoolean(false)
    private var copyThread: Thread? = null

    // 暂停复制
    fun pause() {
        isPaused.set(true)
    }

    // 恢复复制
    fun resume() {
        lock.lock()
        try {
            isPaused.set(false)
            pauseCondition.signal() // 唤醒等待的复制线程
        } finally {
            lock.unlock()
        }
    }

    // 启动复制任务
    fun startCopy(sourcePath: String, targetPath: String) {
        copyThread = Thread {
            val bufferSize = 8 * 1024 * 1024 // 8MB分块,可根据需求调整
            try {
                FileChannel.open(Paths.get(sourcePath), StandardOpenOption.READ).use { sourceChannel ->
                    FileChannel.open(Paths.get(targetPath), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW).use { targetChannel ->
                        var transferred = 0L
                        val fileSize = sourceChannel.size()
                        while (transferred < fileSize) {
                            // 检查是否需要暂停,若暂停则进入等待
                            while (isPaused.get()) {
                                lock.lock()
                                try {
                                    pauseCondition.await()
                                } finally {
                                    lock.unlock()
                                }
                            }
                            // 分块传输数据
                            val bytesTransferred = sourceChannel.transferTo(transferred, bufferSize.toLong(), targetChannel)
                            if (bytesTransferred == 0L) break // 传输完成
                            transferred += bytesTransferred
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
                if (e is InterruptedException) {
                    Thread.currentThread().interrupt() // 保留中断标记
                }
            }
        }
        copyThread?.start()
    }

    // 强制终止复制任务(可选)
    fun stopCopy() {
        copyThread?.interrupt()
        copyThread = null
    }
}

2. 在Main线程中绑定按键事件

在UI层(Dispatchers.Main线程)的按键点击逻辑中,直接调用控制器的对应方法即可实现控制:

// 初始化控制器
val copyController = FileCopyController()

// 启动复制按钮点击事件
startButton.setOnClickListener {
    val source = """D:\Games\Eg.7z"""
    val target = """D:\New folder\Eg.7z"""
    copyController.startCopy(source, target)
}

// 暂停按钮点击事件
pauseButton.setOnClickListener {
    copyController.pause()
}

// 恢复按钮点击事件
resumeButton.setOnClickListener {
    copyController.resume()
}

关键说明

  • 分块传输:通过FileChannel.transferTo()分块处理文件,避免一次性阻塞整个IO操作,让线程有机会检查暂停状态。
  • 线程安全状态:用AtomicBoolean标记暂停状态,配合ReentrantLock和Condition实现线程的等待/唤醒,确保Main线程与IO线程的状态交互安全。
  • 中断处理:若需强制终止任务,可调用stopCopy()中断复制线程,需正确处理InterruptedException以保证线程状态正确。

内容的提问来源于stack exchange,提问作者Cyber Avater

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 02:57:48