Kotlin协程分析之CoroutineScheduler

概述

看这篇文章,可以跳着看,遇到哪个方法不懂就跳到哪个方法去看,上下对照着理解。

常量

companion object {
   
        // A symbol to mark workers that are not in parkedWorkersStack
        @JvmField
        val NOT_IN_STACK = Symbol("NOT_IN_STACK")

        // Worker ctl states
        private const val PARKED = -1    // 在parkedWorkersStack栈上
        private const val CLAIMED = 0    // 初始状态
        private const val TERMINATED = 1 // 终止状态

        // Masks of control state
        /** 
         * |------------------------------------|---------------------|----------------------|
         * |         cpu permit(22bit)          |    BLOCKING(21bit)  |   CREATED(21bit)     |
         * |------------------------------------|---------------------|----------------------|
         */
        private const val BLOCKING_SHIFT = 21 // 2M threads max
        private const val CREATED_MASK: Long = (1L shl BLOCKING_SHIFT) - 1
        private const val BLOCKING_MASK: Long = CREATED_MASK shl BLOCKING_SHIFT
        private const val CPU_PERMITS_SHIFT = BLOCKING_SHIFT * 2
        private const val CPU_PERMITS_MASK = CREATED_MASK shl CPU_PERMITS_SHIFT

        internal const val MIN_SUPPORTED_POOL_SIZE = 1 // we support 1 for test purposes, but it is not usually used
        internal const val MAX_SUPPORTED_POOL_SIZE = (1 shl BLOCKING_SHIFT) - 2

        // Masks of parkedWorkersStack
        /** 
         * |------------------------------------|---------------------|
         * |         PARKED_VERSION(43bit)      |  PARKED_INDEX(21bit)|
         * |------------------------------------|---------------------|
         */
        private const val PARKED_INDEX_MASK = CREATED_MASK
        private const val PARKED_VERSION_MASK = CREATED_MASK.inv()
        private const val PARKED_VERSION_INC = 1L shl BLOCKING_SHIFT
    }

理论上最大支持2M的线程数量

CoroutineScheduler

CoroutineScheduler实现了java的Executor接口,是Dispatchers.Default的调度器,它的调度逻辑就是,IO任务到IO线程中执行,CPU密集任务CPU型线程中去执行,对于调度的任务来说,什么io线程,什么cpu型线程,都是透明的,对任务来说都是线程。

线程池里面的线程名字叫做 DefaultDispatcher-worker-1,DefaultDispatcher-worker-2,DefaultDispatcher-worker-3等之类的。

在这里插入图片描述

public actual object Dispatchers {
   
	@JvmStatic
    public actual val Default: CoroutineDispatcher = DefaultScheduler
}
internal val DEFAULT_SCHEDULER_NAME = systemProp(
    "kotlinx.coroutines.scheduler.default.name", "DefaultDispatcher"
)
internal object DefaultScheduler : SchedulerCoroutineDispatcher(
    CORE_POOL_SIZE, MAX_POOL_SIZE,
    // DEFAULT_SCHEDULER_NAME的值默认就是 "DefaultDispatcher"
    IDLE_WORKER_KEEP_ALIVE_NS, DEFAULT_SCHEDULER_NAME
) {
   
	......
}
internal open class SchedulerCoroutineDispatcher(
    private val corePoolSize: Int = CORE_POOL_SIZE,
    private val maxPoolSize: Int = MAX_POOL_SIZE,
    private val idleWorkerKeepAliveNs: Long = IDLE_WORKER_KEEP_ALIVE_NS,
    // schedulerName的值默认就是 "DefaultDispatcher"
    private val schedulerName: String = "CoroutineScheduler",
) : ExecutorCoroutineDispatcher() {
   

    override val executor: Executor
        get() = coroutineScheduler

    // This is variable for test purposes, so that we can reinitialize from clean state
    private var coroutineScheduler = createScheduler()

    private fun createScheduler() =
    	// 使用 CoroutineScheduler 作为调度器
        CoroutineScheduler(corePoolSize, maxPoolSize, idleWorkerKeepAliveNs, schedulerName)

    override fun dispatch(context: CoroutineContext, block: Runnable): Unit = coroutineScheduler.dispatch(block)

    override fun dispatchYield(context: CoroutineContext, block: Runnable): Unit =
        coroutineScheduler.dispatch(block, tailDispatch = true)

    internal fun dispatchWithContext(block: Runnable, context: TaskContext, tailDispatch: Boolean) {
   
        coroutineScheduler.dispatch(block, context, tailDispatch)
    }

	....
}
internal class CoroutineScheduler(
    // 核心线程数量,保证核心线程的存活,核心线程干cpu密集型任务,io任务(Blocking)不能占有许可(会主动释放)
    @JvmField val corePoolSize: Int,
    // 最大线程数量
    @JvmField val maxPoolSize: Int,
    // 空闲线程可以存活的时间,大于corePoolSize的数量的线程闲下来时都是空闲线程
    @JvmField val idleWorkerKeepAliveNs: Long = IDLE_WORKER_KEEP_ALIVE_NS,
    // 调度器的名字
    @JvmField val schedulerName: String = DEFAULT_SCHEDULER_NAME
) : Executor, Closeable {
   

    // CPU密集型任务队列
    @JvmField
    val globalCpuQueue = GlobalQueue()

    // IO型任务队列
    @JvmField
    val globalBlockingQueue = GlobalQueue()
    
    // 处于parked状态的线程都在这个栈上,这个值是栈顶的值,这个值分成2部分,PARKED_INDEX表示一个workers数组索引位置
    // 通过这个索引可以在workers数组中找到这个worker,另一部分就是版本号,记录被修改的次数
    /** 
     * |------------------------------------|----------------------|
     * |         PARKED_VERSION(43bit)      |  PARKED_INDEX(21bit) |
     * |------------------------------------|--------------------——|
     */
    private val parkedWorkersStack = atomic(0L)
    
    // 存储线程的数组,workers[0]这个位置不用,是null。从1开始才是有效的worker
    @JvmField
    val workers = ResizableAtomicArray<Worker>((corePoolSize + 1) * 2)
    
    /** 
     * |------------------------------------|---------------------|----------------------|
     * |         cpu permit(22bit)          |    BLOCKING(21bit)  |   CREATED(21bit)     |
     * |------------------------------------|---------------------|----------------------|
     */
    // 也就是说这里的cpu permit初始值是corePoolSize
    private val controlState = atomic(corePoolSize.toLong() shl CPU_PERMITS_SHIFT)
	
    // 当前创建的线程数量
    private val createdWorkers: Int inline get() = (controlState.value and CREATED_MASK).toInt()
    
    // cpu permit的数量,初始值是corePoolSize
    private val availableCpuPermits: Int inline get() = availableCpuPermits(controlState.value)
    
    // 计算当前创建的线程数量
    private inline fun createdWorkers(state: Long): Int = (state and CREATED_MASK).toInt()
    // 计算当前阻塞的线程数量
    private inline fun blockingTasks(state: Long): Int = (state and BLOCKING_MASK shr BLOCKING_SHIFT).toInt()
    inline fun availableCpuPermits(state: Long): Int = (state and CPU_PERMITS_MASK shr CPU_PERMITS_SHIFT).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值