協程上下文與Job深入解析


在上一次https://www.cnblogs.com/webor2006/protected/p/12611978.html對於協程的調試與線程之間的切換進行了相關的學習,這次進一步對Job進行進一步的學習,在之前https://www.cnblogs.com/webor2006/p/11730528.html其實已經對Job有了一定的了解,簡單回顧一下:

當時咱們舉的一個等待協程代碼執行完利用到了Job.join()這個方法的例子, 其實關於Job還有更加深入的東西待挖掘,下面來看一下。

Job深入解析:

在上次的咱們使用Job的例子中是通過調用"GlobalScope.launch()"來獲得Job對象的:

因為GlobalScope.launch()本身就是返回的Job對象:

但是!!對於沒有明確返回值Job的場景那又有什么方法能獲取到Job本身呢?比如說:

這個runBlocking的函數的返回值並非是Job的:

此時先來上一個理論說明:

協程的Job是歸屬其上下文(Context)的一部分,Koltin為我們提供了一種簡潔的手段來通過協程上下文獲取到協程自身的Job對象。我們可以通過coroutineContext[Job]表達式來訪問上下文中的Job對象。

還是有些抽象,下面用例子來進行說明:

運行看一下:

此時咱們可以添加上一次https://www.cnblogs.com/webor2006/protected/p/12611978.html學習的協程調試的JVM參數再來看一下協程的信息:

再運行:

程序雖簡單,但是這里面蘊藏的細節還是相當多的,目前而言存在如下幾個疑點:

1、coroutineContext從哪來的,為啥可以直接使用?

2、為啥可以直接使用[]來調用,背后我猜肯定是用了運算符重載了,實際是否如猜想呢?

3、 為啥咱們可以直接使用這個Job,它又是哪里來的?

4、為啥輸出結果是它?

以上四個問題,下面則來一一進行剖析。

剖析Job協程上下文的原理:

接下來則從上面的四個疑問的問題尋找其整個背后的原理。

疑問一:coroutineContext從哪來的,為啥可以直接使用?

點擊進去查看一下它:

原來它是在CoroutineScope接口里所定義的一個屬性, 而CoroutineScope接口有很多具體的實現類,根據咱們的輸出結果來看看到了一個“BlockingCoroutine”,它就是具體的子類之一:

打開瞅一下這個具體類:

而這個context的值又是來自於上面這兩個屬性來構成:

而runBlocking()里面的代碼塊就是運行在CoroutineScope中的:

很明顯咱們就可以在這個協程代碼塊中直接使用coroutineContext了:

咱們再來讀一下該屬性的說明:

從文檔說明中也能看到,代碼中要訪問這個屬性唯一的使用就是訪問Job,所以正好是咱們目前所使用的代碼形式,目前此問題就已經解決了。

疑問二:為啥可以直接使用[]來調用,背后我猜肯定是用了運算符重載了,實際是否如猜想呢?

這里還是從源碼來找答案:

此時看一下CoroutineContext這個類:

而看它里面有一個操作符的重載,如我們所猜想:

 

所以這也是為啥咱們是用的可空類型來接收:

關於operator fun的寫法在之前https://www.cnblogs.com/webor2006/p/11369333.html的屬性委托有過使用,而之所以可以使用[]表達式來訪問,這個語法在之前倒還木有學到,這里參考一下這位博主的說明:https://www.jianshu.com/p/e265dbcfe009,其中看一個例子就明白了:

而我們訪問時就可以這樣:

回到咱們這個重載函數的定義:

很明顯咱們也可以用[]來訪問這個重載符函數,其中接收的參數是一個Key類型,所以最終我們看到這樣的寫法了:

此問題就已經明白了。

疑問三:為啥咱們可以直接使用這個Job,它又是哪里來的?

接下來解決最后一個疑點,既然我們在第二個問題分析中可以看出實際是要傳一個Key類型的,但是為啥我們傳了一個Job呢?

 

Job和Key之間肯定有聯系,下面來剖析一下:

咱們先來看一下Key的定義:

 

好,此時再來看一下我們調用時傳遞的Job的定義:

很明顯,我們直接能傳遞這個Job的原因就是由於在里面定有伴生對象所達成的,關於伴生對象可以參考https://www.cnblogs.com/webor2006/p/11210181.html,這塊的答案就可以揭曉了。

疑問三:為啥輸出的Job是BlockingCoroutine?

點擊瞅一下它的定義:

而這個BlockingCoroutine的繼承體系如下:

 

所以,最后這個疑點也解決了。

最后再來修改一下程序:

 

然后咱們來看一下這個isActive的定義:

而從它的實現細節就可以看到確實如文檔所說:

咱們來試一下:

而這個的isActive是定義在Job里面的:

那,研究這個細節有啥意義呢?結論就是:對於協程是否是isActive其實是取決於它的Job是不是isActive

 

以上則對於這個非常簡單的例子來完整的闡述了它里面背后的原理,雖說程序簡單,但是要搞清楚其背后機制還是不簡單的,通過這樣的一個徹底分析,對於協程、協程上下文、Job之間的關系也更進一步的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM