封装一个简单的线程池工具

133 阅读3分钟

几个注意点

  • ReentrantLock 和 Condition 用于唤醒和线程休眠

  • 通过 ThreadFactory 来创键线程,重写 beforeExecute,afterExecute 来处理逻辑

  • kotlin 通过 @Synchronized 注解,来简便的使用锁

    需要解决

    • 怎样实现按优先级来执行?
    • 怎样让任务执行的结果,最终回调到主线程?

    怎样实现按优先级来执行?

    通过 PriorityBlockingQueue + 一个实现 Comparable 接口的 Runnable 来实现

    由于 PriorityBlockingQueue 是一个按优先级顺序排列的阻塞队列,它在使用上需要我们实现对比优先级的代码

    我们通过实现 Comparable 的 compareTo() : Int, 这里通过返回的 Int 值决定优先级:

    1. 如果两个元素的 compareTo() 方法返回 0,则两个元素具有相同的优先级

    2. 如果两个元素的 compareTo() 方法返回负数,则第一个元素的优先级高于第二个元素。

    3. 如果两个元素的 compareTo() 方法返回正数,则第一个元素的优先级低于第二个元素。

    怎样让任务执行的结果,最终回调到主线程?

    在我看来,可以拆分成两个小问题:

    • 返回执行的结果

    • 将结果回调到主线程中(使用 Handler.post 到主线程中执行)

实现代码

/**
 * 优先级比较的 Runnable
 */
class PriorityRunnable(val priority : Int, val runnable: Runnable) : Runnable,Comparable<PriorityRunnable>{

    override fun run() {
        runnable.run()
    }

    override fun compareTo(other: PriorityRunnable): Int {
        // 优先级的计算方式
        //具体来说,PriorityBlockingQueue 会将元素按照以下规则进行排序:
        //如果两个元素的 compareTo() 方法返回 0,则两个元素具有相同的优先级。
        //如果两个元素的 compareTo() 方法返回负数,则第一个元素的优先级高于第二个元素。
        //如果两个元素的 compareTo() 方法返回正数,则第一个元素的优先级低于第二个元素。
        return  if (priority > other.priority) 1 else if (priority < other.priority) -1 else 0
    }
}


/**
 * 线程池工具 (CPU 密集型),支持暂停/恢复
 * 可用于批量上传下载
 * 按优先级的顺序来执行
 *
 */
object KExecutors {

    private val TAG = "KExecutors"
    private var mKExecutor: ThreadPoolExecutor

    // 用来实现暂停和恢复执行
    private val mLock = ReentrantLock()
    private val mCondition = mLock.newCondition()
    private var mPaused = false

    // 执行结果发送到主线程中
    private val mHandler = Handler(Looper.getMainLooper())

    init {
        val coreThreadSize = Runtime.getRuntime().availableProcessors() + 1
        val maxThreadSize = coreThreadSize * 2 + 1
        val keepAliveTime = 20L
        val unit = TimeUnit.SECONDS
        val queue = PriorityBlockingQueue<Runnable>()
        val threadName = AtomicLong()

        val threadFactory = ThreadFactory {
            val thread = Thread(it)
            thread.name = "KLib-Thread-" + threadName.getAndIncrement()
            return@ThreadFactory thread
        }

        mKExecutor = object : ThreadPoolExecutor(
            coreThreadSize,
            maxThreadSize,
            keepAliveTime,
            unit,
            queue,
            threadFactory
        ) {
            override fun beforeExecute(t: Thread?, r: Runnable?) {
                // 判断是否已经暂停了,如果暂停就不要执行了
                if (mPaused) {
                    mLock.lock()
                    try {
                        mCondition.await()
                    } finally {
                        mLock.unlock()
                    }
                }
            }

            override fun afterExecute(r: Runnable?, t: Throwable?) {
                // 打印当前工作线程数
                r as PriorityRunnable
                Log.e(TAG, "已经执行完成的线程的优先级为" + r.priority)
                // 打印线程任务的执行时间
            }
        }
    }

    fun execute(@IntRange(from = 0, to = 10) priority: Int = 0, runnable: Runnable) {
        mKExecutor.execute(PriorityRunnable(priority, runnable))
    }

    /**
     * 将返回值 post 到主线程的方法
     * <*> 表示可以为任意值
     */
    fun executeCallable(@IntRange(from = 0, to = 10) priority: Int = 0, callable: Callable<*>) {
        mKExecutor.execute(PriorityRunnable(priority, callable))
    }

    /**
     * 这里调用 pause,已经加入的任务不会马上暂停,会在执行下一个任务前判断
     * 具体见  beforeExecute() 中实现
     */
    @Synchronized
    fun pause() {
        mPaused = true
        Log.e(TAG, "pause")
    }


    /**
     * 唤醒
     *  Synchronized 用于多线程调用加锁
     *  Condition 用于唤醒线程
     */
    @Synchronized
    fun resume() {
        mPaused = false
        mLock.lock()
        try {
            // 唤醒所有阻塞的线程
            mCondition.signalAll()
        } finally {
            mLock.unlock()
        }
        Log.e(TAG, "resume")
    }

    @Synchronized
    fun isPaused(): Boolean {
        return mPaused
    }


    /**
     * 执行代返回值的
     */
    abstract class Callable<T> : Runnable {
        abstract fun onBeforeRun()
        abstract fun onBackground(): T
        abstract fun onCompleted(t: T)

        override fun run() {
            mHandler.post {
                onBeforeRun()
            }
            val t = onBackground()
            mHandler.post {
                onCompleted(t)
            }
        }
    }
}

相关链接