<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 協程的基本操作 ### 協程掛起 在協程程序中,CommonPool表示共享線程池,ForkJoinPool表示所有在該線程池中的線程可以嘗試去執行其他線程創建的子任務,在這個線程池中很少有線程處于空閑狀態。delay()函數類似于Thread.sleep(),都表示使程序延遲操作,但是delay()函數不會阻塞線程,只是掛起協程本身,當協程在等待時,線程將返回到線程池中,當協程等待完成時,將使用在線程池中的空閑線程來恢復程序繼續執行。接下來我們通過一個案例來演示協程掛起的操作,具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.launch fun main(args: Array<String>) { launch(CommonPool) { println("打印前的線程${Thread.currentThread()}") delay(1000L) println("hello") println("打印后的線程${Thread.currentThread()}") } //啟動另外一個協程 launch(CommonPool) { delay(1000L) println("tom") } println("world") Thread.sleep(2000L) } ``` 運行結果: ``` world 打印前的線程Thread[ForkJoinPool.commonPool-worker-1,5,main] hello 打印后的線程Thread[ForkJoinPool.commonPool-worker-2,5,main] tom ``` 由于協程是由程序直接實現的一種輕量級線程,多線程的執行順序是不固定的,字符串“hello”與“tom”是在兩個協程中打印的,因此該程序的運行結果中打印的字符串“hello”與“tom”的順序是不固定的。從運行結果可知,協程在延遲之前,第7行代碼打印的當前執行的線程名稱是“Thread[ForkJoinPool.commonPool-worker-1,5,main]”,當程序執行delay()函數之后就把協程掛起來了,當前執行的線程就進入到線程池中。當協程的延遲時間到了之后,程序會自動從線程池中找到一個空閑的線程把程序恢復,該程序中使用的恢復線程的名稱是“Thread[ForkJoinPool.commonPool-worker-2,5,main]”,這個空閑線程是隨機選取的,有可能還是線程“Thread[ForkJoinPool.commonPool-worker-1,5,main]”。如果將程序中的delay()函數替換為Thread.sleep(),則在這個程序中一直都用同一個線程,無論延時多久,都用“Thread[ForkJoinPool.commonPool-worker-1,5,main]”線程來執行程序,此時這個線程就是阻塞式的。 ### 掛起函數 掛起函數主要是通過suspend來修飾的一個函數,這個函數只能在協程代碼內部調用,非協程代碼不能調用。在前面小節中講到delay()函數是一個掛起函數,當在程序中調用掛起函數時,在當前文件的左側可以看到[插圖]這樣一個圖標。一般出現這個圖標時,就說明調用的是suspend修飾的掛起函數。除了API中提供的掛起函數之外,還可以自定義一個掛起函數。接下來我們通過suspend來創建一個掛起函數,具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.launch //掛起函數 suspend fun hello() { delay(1000L) println("I am lucy") } fun main(args: Array<String>) { //協程代碼調用掛起函數 launch(CommonPool) { hello() } Thread.sleep(2000L) //睡眠2000L } ``` 運行結果: ``` I am Lucy ``` 上述代碼中,在第6行通過suspend創建了一個掛起函數hello(),然后在協程中調用掛起函數。需要注意的是,只有協程代碼才可以調用掛起函數,非協程代碼不能調用掛起函數hello(),如果調用,則編譯器會報錯。 ### 主協程 根據上一小節可知,掛起函數可以在協程代碼中調用,由于主協程也屬于協程,因此在主協程中也可以調用掛起函數。主協程主要用runBlocking來表示,主協程有兩種表達方式,一種方式是通過“:Unit=runBlocking”定義,另一種方式是通過“runBlocking{}”代碼塊的形式定義。接下來我們通過一個案例來演示主協程的兩種定義方式。 #### :Unit=runBlocking 使用:Unit=runBlocking定義主協程,通過主協程來延遲1秒打印world,具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.runBlocking fun main(args: Array<String>):Unit= runBlocking { println("hello") delay(1000L) //睡眠1000秒鐘打印world println("world") } ``` 運行結果: ``` hello world ``` #### runBlocking{} 使用runBlocking{}定義主協程,通過主協程來延遲1秒打印world,具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.runBlocking fun main(args: Array<String>) { println("hello") runBlocking { delay(1000L) //睡眠1000L秒鐘打印world } println("world") } ``` 運行結果: ``` hello world ``` ### 協程中的Job任務 協程可以通過launch()函數來啟動,這個函數的返回值是一個Job類型的任務。這個Job類型的任務是協程創建的后臺任務,它持有協程的引用,因此它代表當前協程的對象。獲取Job類型的任務作用是判斷當前任務的狀態。Job任務的狀態有3種類型,分別是New(新建的任務)、Active(活動中的任務)、Completed(已結束的任務)。Job任務中有兩個字段,分別是isActive(是否在活動中)和isCompleted(是否停止),通過這兩個字段的值可判斷當前任務的狀態。表9-1介紹了Job任務的3種狀態。 | Job狀態 |isActive | isCompleted | | --- | --- | --- | | New(新建的活動) | false | false | | Active(活動中) | true | false | | Completed (已結束) | false | true | 接下來我們通過一個案例來打印程序中任務的狀態,具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.experimental.launch fun main(args: Array<String>) { val job: Job = launch(CommonPool) { delay(1000L) println("hello") } println("主線程睡眠前:isActive=${job.isActive} isCompleted=${job.isCompleted}") println("world") Thread.sleep(2000L) //job.join(); println("主線程睡眠后:isActive=${job.isActive} isCompleted=${job.isCompleted}") } ``` 運行結果: ``` 主線程睡眠前:isActive=true isCompleted=false world hello 主線程睡眠后:isActive=false isCompleted=true ``` 上述代碼中,協程函數launch()返回的是一個Job類型的任務,在主線程睡眠之前和睡眠之后分別打印這個Job類型的任務狀態。根據運行結果可知,主線程睡眠之前,Job任務狀態中的字段isActive的值為true,isCompleted的值為false,表示該任務是在活動中。主線程睡眠之后,Job任務狀態中的字段isActive的值為false,isCompleted的值為true,表示該任務已經是結束狀態。 >[success] **多學一招:協程中的join()函數** 如果去掉上面示例中的第13行代碼后,程序運行的結果只會輸出world字符串,不會輸出hello字符串,這是因為協程中啟動的是一個守護線程,當主線程完成之后,協程就會被銷毀掉,因此協程中的代碼就不會再執行。如果想輸出hello字符串,除了使用Thread.sleep(2000L)語句之外,還可以使用Java線程中的join()函數,該函數表示的是當前任務執行完成之后再執行其他操作,也就是可以將上面示例中的第13行代碼換成“job.join()”,此時由于join()函數是一個掛起函數,因此需要將上面示例中的main()函數設置為主協程,修改后的具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.* fun main(args: Array<String>):Unit= runBlocking { val job: Job = launch(CommonPool) { delay(1000L) println("hello") } println("主線程睡眠前:isActive=${job.isActive} isCompleted=${job.isCompleted}") println("world") job.join() //協程執行完之后再執行其他操作 println("主線程睡眠后:isActive=${job.isActive} isCompleted=${job.isCompleted}") } ``` 運行結果: ``` 主線程睡眠前:isActive=true isCompleted=false world hello 主線程睡眠后:isActive=false isCompleted=true ``` ### 普通線程和守護線程 在Kotlin中的線程分為普通線程和守護線程。普通線程是通過實現Thread類中的Runnable接口來創建的一個線程;守護線程就是程序運行時在后臺提供通用服務的一種線程,例如垃圾回收線程就是一個守護線程。如果某個線程對象在啟動之前調用了isDaemon屬性并將其設置為true,則這個線程就變成了守護線程。接下來我們通過一個案例來演示如何將普通線程轉化為守護線程,具體代碼如下所示。 ``` class DaemonThread : Runnable { override fun run() { while (true) { println(Thread.currentThread().name + "---is running") } } } fun main(args: Array<String>) { println("main線程是守護線程嗎?" + Thread.currentThread().isDaemon) val dt = DaemonThread() //創建一個DaemonThread對象dt val t = Thread(dt, "守護線程") //創建線程t共享dt資源 println("t線程默認是守護線程嗎?" + t.isDaemon) //判斷是否為守護線程 t.isDaemon = true //將線程t設置為守護線程 t.start() //調用start()方法開啟線程t for (i in 1..3) { println(i) } } ``` 運行結果: ``` main線程是守護線程嗎?false t線程默認是守護線程嗎?false 1 2 3 守護線程——is running 守護線程——is running 守護線程——is running 守護線程——is running 守護線程——is running ``` 上述代碼中,子線程t是一個普通線程,在開啟線程t之前,設置其isDaemon的屬性值為true,此時子線程t就變為了守護線程。當開啟守護線程t之后,程序會執行死循環中的打印語句,當主線程死亡后,JVM會通知守護線程。由于守護線程從接收指令到做出響應需要一定的時間,因此打印了幾次“守護線程——is running”語句后,守護線程結束。 >[info] **注意** 要將某個線程設置為守護線程,必須在該線程啟動之前,也就是說isDaemon屬性的設置必須在start()方法之前調用,否則會引發IllegalThreadStateException異常。 ### 線程與協程效率對比 一般情況下,線程有很多缺點,例如當啟動一個線程的時候需要通過回調方式進行異步任務的回調,代碼寫起來比較麻煩。而且啟動線程時占用的資源比較多,啟動協程時占用的資源相對來說比較少。接下來我們分別通過線程和協程來打印10萬個點,來對比一下線程和協程所耗費的時間,也就是對比兩者運行時效率的高低。 #### 線程執行效率 通過線程來打印100 000個點,并輸出程序運行時耗費的時間,具體代碼如下所示。 ``` fun main(args: Array<String>) { val start = System.currentTimeMillis() //獲取開始時間 //創建線程 val list1 = List(100000, { Thread(Runnable { println(".") }) }) list1.forEach { it.start() //開啟每個線程 } list1.forEach { it.join() //使每個線程執行完之后再執行后續操作 } val end = System.currentTimeMillis() //獲取結束時間 println("總耗時:${end - start}") } ``` 運行結果: ``` 總耗時:20197 ``` #### 協程執行效率 通過協程來打印100 000個點,并輸出程序運行時耗費的時間,具體代碼如下所示。 ``` import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.runBlocking fun main(args: Array<String>):Unit=runBlocking{ val start = System.currentTimeMillis() //獲取開始時間 //創建協程 val list2 = List(100000) { launch { println(".") } } list2.forEach { it.join() } val end = System.currentTimeMillis() println("總耗時:${end-start}") } ``` 運行結果: ``` 總耗時:958 ``` 根據上述兩個文件的運行結果可知,協程的效率比線程要高很多。協程是依賴于線程存在的,協程啟動之后需要在線程中來執行,但是啟動100 000個協程并不代表啟動了100 000個線程,協程可以將程序中的定時操作或者延時操作掛起來,啟動100 000個協程可能只需要5、6個線程就可以完成。對于線程來說,啟動100 000個線程,就需要這么多資源,并且線程之間進行切換時也需要耗費很多時間,因此線程的效率就比較低。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看