publicopenclassJobSupportconstructor(active: Boolean) : Job, ChildJob, ParentJob, SelectClause0 { internalfuninitParentJobInternal(parent: Job?) { assert { parentHandle == null } if (parent == null) { parentHandle = NonDisposableHandle return } parent.start() // make sure the parent is started val handle = parent.attachChild(this) parentHandle = handle // now check our state _after_ registering (see tryFinalizeSimpleState order of actions) if (isCompleted) { handle.dispose() parentHandle = NonDisposableHandle // release it just in case, to aid GC } } }
privatefuncontinueCompleting(state: Finishing, lastChild: ChildHandleNode, proposedUpdate: Any?) { assert { this.state === state } // consistency check -- it cannot change while we are waiting for children // figure out if we need to wait for next child val waitChild = lastChild.nextChild() // try wait for next child if (waitChild != null && tryWaitForChild(state, waitChild, proposedUpdate)) return// waiting for next child // no more children to wait -- try update state val finalState = finalizeFinishingState(state, proposedUpdate) afterCompletion(finalState) }
internalfuncancelImpl(cause: Any?): Boolean { var finalState: Any? = COMPLETING_ALREADY if (onCancelComplete) { // make sure it is completing, if cancelMakeCompleting returns state it means it had make it // completing and had recorded exception finalState = cancelMakeCompleting(cause) if (finalState === COMPLETING_WAITING_CHILDREN) returntrue } if (finalState === COMPLETING_ALREADY) { finalState = makeCancelling(cause) } returnwhen { finalState === COMPLETING_ALREADY -> true finalState === COMPLETING_WAITING_CHILDREN -> true finalState === TOO_LATE_TO_CANCEL -> false else -> { afterCompletion(finalState) true } } }
// 这里的 list 即是上面添加了 handler 的 list privatefunnotifyCancelling(list: NodeList, cause: Throwable) { // first cancel our own children onCancelling(cause) // 会循环执行上面添加的 ChildHandleNode 的 invoke 方法 notifyHandlers<JobCancellingNode<*>>(list, cause) // 可能取消父协程 cancelParent(cause) // tentative cancellation -- does not matter if there is no parent }
// The method that is invoked when the job is cancelled to possibly propagate cancellation to the parent. // Returns `true` if the parent is responsible for handling the exception, `false` otherwise. // never returns `false` for instances of [CancellationException], otherwise such exception // may leak to the [CoroutineExceptionHandler]. privatefuncancelParent(cause: Throwable): Boolean { // isScopedCoroutine 为 true 则不传播且不取消父协程直接返回,默认为false,子类可以重写 if (isScopedCoroutine) returntrue
/* CancellationException is considered "normal" and parent usually is not cancelled when child produces it. * This allow parent to cancel its children (normally) without being cancelled itself, unless * child crashes and produce some other exception during its completion. */ val isCancellation = cause is CancellationException val parent = parentHandle // No parent -- ignore CE, report other exceptions. if (parent === null || parent === NonDisposableHandle) { return isCancellation }
// JobSupport // Child was cancelled with a cause. In this method parent decides whether it cancels itself // It is overridden in supervisor implementations to completely ignore any child cancellation. // Returns `true` if exception is handled, `false` otherwise (then caller is responsible for handling an exception) publicopenfunchildCancelled(cause: Throwable): Boolean { if (cause is CancellationException) returntrue return cancelImpl(cause) && handlesException }
funmain() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("CoroutineExceptionHandler got $exception") } val job = GlobalScope.launch(handler) { launch { // 第一个子协程 try { delay(Long.MAX_VALUE) } finally { withContext(NonCancellable) { println("Children are cancelled, but exception is not handled until all children terminate") delay(100) println("The first child finished its non cancellable block") } } } launch { // 第二个子协程 delay(10) println("Second child throws an exception") throw ArithmeticException() } } job.join() }
// output Second child throws an exception Children are cancelled, but exception is not handled until all children terminate The first child finished its non cancellable block CoroutineExceptionHandler got java.lang.ArithmeticException
publicfinaloverridefunresumeWith(result: Result<T>) { // 通过 result 获取 state val state = makeCompletingOnce(result.toState()) if (state === COMPLETING_WAITING_CHILDREN) return afterResume(state) }
privatefuntryMakeCompletingSlowPath(state: Incomplete, proposedUpdate: Any?): Any? { val list = getOrPromoteCancellingList(state) ?: return COMPLETING_RETRY val finishing = state as? Finishing ?: Finishing(list, false, null) var notifyRootCause: Throwable? = null synchronized(finishing) { if (finishing.isCompleting) return COMPLETING_ALREADY finishing.isCompleting = true if (finishing !== state) { if (!_state.compareAndSet(state, finishing)) return COMPLETING_RETRY } val wasCancelling = finishing.isCancelling (proposedUpdate as? CompletedExceptionally)?.let { finishing.addExceptionLocked(it.cause) } // If it just becomes cancelling --> must process cancelling notifications notifyRootCause = finishing.rootCause.takeIf { !wasCancelling } } // process cancelling notification here -- it cancels all the children _before_ we start to to wait them (sic!!!) notifyRootCause?.let { notifyCancelling(list, it) } val child = firstChild(state) // now wait for children if (child != null && tryWaitForChild(finishing, child, proposedUpdate)) return COMPLETING_WAITING_CHILDREN // otherwise -- we have not children left (all were already cancelled?) return finalizeFinishingState(finishing, proposedUpdate) }
可知当协程抛出异常后,会调用 notifyCancelling 方法,该方法在上面已经解析过了。
因此,当协程发生异常时会取消它的所有子协程,默认会取消它的父协程。
接下来看看 finalizeFinishingState 方法:
1 2 3 4 5 6 7 8
privatefunfinalizeFinishingState(state: Finishing, proposedUpdate: Any?): Any? { // ... if (finalException != null) { val handled = cancelParent(finalException) || handleJobException(finalException) if (handled) (finalState as CompletedExceptionally).makeHandled() } // ... }
publicfunhandleCoroutineException(context: CoroutineContext, exception: Throwable) { try { // 定义了 CoroutineExceptionHandler 则由它处理 context[CoroutineExceptionHandler]?.let { it.handleException(context, exception) return } } catch (t: Throwable) { handleCoroutineExceptionImpl(context, handlerException(exception, t)) return } // If a handler is not present in the context or an exception was thrown, fallback to the global handler handleCoroutineExceptionImpl(context, exception) }