網站首頁 編程語言 正文
1.協程
協程不是進程或線程,它的執行過程更類似于子例程或者說不帶返回值的函數調用。
一個程序可以包含多個協程,類似于一個進程包含多個線程。線程有自己的上下文多個線程存在時它們相對獨立,切換受系統控制,而協程也相對獨立,也有自己的上下文,但是切換是由自己控制的,當需要切換到其他協程時是由當前協程控制的。
線程 | 協程 | |
---|---|---|
獨立性 | 相對獨立 | 相對獨立 |
上下文 | 有自己的上下文 | 有自己的上下文 |
切換 | 系統決定是否切換 | 當前協程決定是否切換 |
2.Kotlin協程
1.引入Kotlin協程
Kotlin中如果要使用協程是需要添加依賴的,它沒有被集成在標準庫中,單獨拎出來主要是為了減小標準庫的體積
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
那么要如何理解Kotlin協程?Kotlin協程可以理解為更輕量級的線程,協程的運行離不開線程,這有點像線程和進程之間的關系。
2.Kotlin協程的使用
fun main() = runBlocking { doWorld() } suspend fun doWorld() = coroutineScope { launch { delay(1000L) println("World!") } println("Hello") } //輸出結果: //Hello //World!
上面的代碼是Kotlin協程的一個簡單例子其中runBlocking
、coroutineScope
、launch
是協程作用域,suspend
是掛起,delay(1000L)
是一個延時函數。從結果來看我們的代碼順序和輸出結果的順序不一樣,這就是Kotlin協程的魅力,我們看下面的流程圖:
3.Kotlin協程的輕量(總結的還不夠清晰)
- 啟動 10 億個線程,這樣的代碼運行在大部分的機器上都是會因為內存不足等原因而異常退出的。那么啟動10億個協程則不會出現異常因為協程是非常輕量的;
- 協程雖然是運行在線程上的但是它并不會與某個線程綁定,而且還可以在不同線程之間切換。
4.協程的“非阻塞式”
線程是阻塞的,因為它在運行一個耗時任務時只有這個任務完成了才會執行后面的任務,而Kotlin在執行一個耗時任務時會把這個任務放入后臺執行,去執行下一個任務。
fun main() { repeat(3) { Thread.sleep(1000L) println("Print-1:${Thread.currentThread().name}") } repeat(3) { Thread.sleep(900L) println("Print-2:${Thread.currentThread().name}") } } /* 輸出結果: Print-1:main Print-1:main Print-1:main Print-2:main Print-2:main Print-2:main */
上面的代碼是阻塞式任務,可以看到兩個任務之間的等待時差是100毫秒,但是第二個repeat執行的前提是第一個repeat執行完畢,那么這個任務的最終耗時就是5700毫秒。
fun main() = runBlocking { launch { repeat(3) { delay(1000L) println("Print-1:${Thread.currentThread().name}") } } launch { repeat(3) { delay(900L) println("Print-2:${Thread.currentThread().name}") } } delay(3000L) } /* 輸出結果: Print-2:main @coroutine#3 Print-1:main @coroutine#2 Print-2:main @coroutine#3 Print-1:main @coroutine#2 Print-2:main @coroutine#3 Print-1:main @coroutine#2 */
上面的代碼是非阻塞式任務,可以看到兩個任務之間的等待時差是100毫秒,第以個repeat和第二個repeat是同時執行的,也就是說他們同時開始執行,當達到900毫秒時第二個repeat開始執行,當達到1000毫秒時第一個repeat開始執行,那么這個任務的最終耗時就是3000毫秒。
由此可見,Kotlin 協程的“非阻塞”其實只是語言層面的,當我們調用 JVM 層面的 Thread.sleep() 的時候,它仍然會變成阻塞式的。與此同時,這也意味著我們在協程當中應該盡量避免出現阻塞式的行為。盡量使用 delay,而不是 sleep。
到這里其實就會產生一個疑問,delay
就能解決阻塞的問題嗎?答案是不是,解決阻塞問題的其實是Kotlin的掛起和恢復的能力,這是協程才擁有的特殊能力。
掛起和恢復又該怎么理解呢,舉個例子,現在有兩件事情:①燒一壺水燒開后斷開電源;②做飯;第一件事是一個耗時任務,開始燒水后我去做第二件事這就是掛起,當水燒開以后要去斷開電源這就是恢復。
5.建立思維模型
Kotlin的協程要比Java線程更抽象,因為Java的線程可以找到Thread的源碼,同時線程也是操作系統中的一個概念,所以理解起來較為簡單。而Kotlin的協程沒有類似的知識點可以建立關聯,所以在學習Kotlin協程的時候就需要簡歷協程的思維模型, 沒有這個思維理解Kotlin協程就比較難。
如何建立Kotlin的思維模型?可以將Kotlin協程想象成一個“更加輕量級的線程”。
從包含關系上看,協程跟線程的關系,有點像線程與進程的關系,畢竟協程不可能脫離線程運行。所以,協程可以理解為運行在線程當中的、更加輕量的 Task。
原文鏈接:https://juejin.cn/post/7171677203384500238
相關推薦
- 2022-07-19 iptables限制docker端口禁止對某臺主機進行提供服務
- 2022-07-03 C#入門之定義類成員與接口實現_C#教程
- 2022-09-03 Matplotlib中文亂碼的兩種詳細解決方案_python
- 2022-09-17 Python高效處理大文件的方法詳解_python
- 2022-07-23 C#文件路徑Path類介紹_C#教程
- 2024-02-16 SpringBoot 攔截器Intercepto的創建與基本使用
- 2022-08-19 Git代碼合并之使用 rebase 整理提交歷史
- 2023-10-12 react函數式組件的useEffect
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支