在之前https://www.cnblogs.com/webor2006/p/11731763.html咱们写过这样的一个例子,先来回顾一下:
![](https://i-blog.csdnimg.cn/blog_migrate/001f94f72ec6af54adba4dd40ba5c90f.gif)
也就是来演示runBlocking与coroutineScope之间的异同点,当时还阐述了一个对它的理论描述,也来回顾一下:
![](https://i-blog.csdnimg.cn/blog_migrate/3502f0d46464a8ec86bda37ed8ce57f2.png)
这里再开个篇幅来提出的原因是在于。。这里面有一些深层次的东东需要再次挖掘,而问题的焦点是在:
![](https://i-blog.csdnimg.cn/blog_migrate/d519e769658adeb9637ca344716e1f0c.png)
回到代码根据这段文字的理解照理应该是这样的嘛:
![](https://i-blog.csdnimg.cn/blog_migrate/bb0064bb7d186f0d3f5a787a4688a7b5.png)
结果肯定不是我们现在所质疑的观点啦,所以这也是需要再单独拎出来值得探讨的东东,这是因为关于runBlocking和coroutineScope是有更加深层的原因的,下面先来阐述一下:
1、runBlocking并非挂起函数;也就是说,调用它的线程会一直位于该函数中,直到协程执行完毕为止。
2、coroutineScope是挂起函数;也就是说,如果其中的协程挂起,那么coroutineScope函数也会挂起。这样,创建coroutineScope的外层函数就可以继续在同一个线程中执行了,该线程会【逃离】coroutineScope之外,并且可以做其他一些事情。
咱们来看一下runBlocking函数的定义:
![](https://i-blog.csdnimg.cn/blog_migrate/a2a8797e1c4ada1c0eab05d3d1828590.png)
再来看一下coroutineScope函数的定义:
![](https://i-blog.csdnimg.cn/blog_migrate/bde25e691e2a8994895f0b057d4541a0.png)
说实话对于上面的理论描述有点难以理解,怎么最终的welcome的输出是在最后打印的而非咱们预期理解的要立马打印出来,其实需要这样来理解:
![](https://i-blog.csdnimg.cn/blog_migrate/c6e4a1ec884794022c7cd85915190b84.png)
所以很明显“welcome”肯定是最后才会被打印出来的,但是!!!貌似上面的有点像是coroutineScope函数阻塞了当前线程,这个观点又与这个理论貌似矛盾了呀:
![](https://i-blog.csdnimg.cn/blog_migrate/99fdfd1bb8331bdae3d87206beb1e91e.png)
其实这个理论是没任何问题的,就是理解上需要这样来理解,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/695ee875d58b6e5b6a3766f0a384a385.png)
如果说coroutineScope是阻塞了当前线程,也就不可能能执行到这句代码:
![](https://i-blog.csdnimg.cn/blog_migrate/7c7fb860a446c5f969b9e0f7eca19fab.png)
![](https://i-blog.csdnimg.cn/blog_migrate/27892d22f9e245de9296b35193c6213a.png)
所以这也能论证coroutineScope确实是不会阻塞当前线程的,而当跳出到runBlocing代码时,它里面会有一个事件循环:
![](https://i-blog.csdnimg.cn/blog_migrate/6141062ee4b5f634040e26645e54cf04.png)
当事件发生时则就会触发事件,也就类似于当休眠完之后就要开始打印语句了,也就相当于事件触发了,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/846767e63dfcbbfe865b17af08af9528.png)
这也就是为啥这句话能打印出来的原因,也就是说,其coroutinScope的真正流程是它会将调度返回给外层runBlocking里面的代码,而且是coroutineScope之上的代码,而非之下的代码,而welcome为啥是最后才打印的真正原因绝对不是因为coroutinScope将线程的代码给阻塞了,这一点确实是比较难理解!!
好,下面了解了这些深层次的理论之后,咱们再以更加正确的姿势来解读一下整个程序的执行流程:
![](https://i-blog.csdnimg.cn/blog_migrate/d775f5fba4078b9acd1354bd1a05a366.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc350d0d94944983d32039a85f66ce26.png)
接下来线程就会碰到coroutineScope挂起函数了:
![](https://i-blog.csdnimg.cn/blog_migrate/74789f31cc25b74f4f4f4a462e71e0fa.png)
当遇到挂起函数时,就需要立马来区分它之上的代码和之下的代码,记住一点它之下的代码一定是需要等待coroutineScope中的协程代码整个执行完了才能被执行到【如果这个先提观点不知道那整个流程就确实是比较难解释了,这个一定得要有这种概念】,而:
![](https://i-blog.csdnimg.cn/blog_migrate/201cb9ae64a781d3420005c07f911307.png)
另外一点是当线程遇到了挂起函数会立马从它往上返回,也就是返回到这块代码:
![](https://i-blog.csdnimg.cn/blog_migrate/59a40bbc99c47910566b3667d4de53a2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d9486d269a2bae5c8b143f3977bcda2b.png)
接下来由于延时到了,接着coroutineScope中的这段代码会得到执行:
![](https://i-blog.csdnimg.cn/blog_migrate/057cd0d715d081e080521646c6aa4b41.png)
![](https://i-blog.csdnimg.cn/blog_migrate/81bbf2f9d97308bb01b9dc8ebdd7e105.png)
接着10s过后,里面的协程这块代码就会被打印了:
![](https://i-blog.csdnimg.cn/blog_migrate/bb4ce444c1b610e688ebbdf8d6ecacbb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/569530983a519f12daa33b8a3bc11300.png)
当这个打印完成,则整个coroutineScope中的协程都执行完了,那该挂起函数也就可以退出了,最后就可以执行挂起函数之下的代码,也就是:
![](https://i-blog.csdnimg.cn/blog_migrate/375bd11b0d183e8f41e22849c08a2080.png)
所以:
![](https://i-blog.csdnimg.cn/blog_migrate/93a92e4a9317638e16ae0bff189ba623.png)
至此!!整个流程就再次以一个全新的视角分析完了~~ 虽说是比较细节,但是对于整个协程的认知理解是非常之重要的!!