協(xié)程
1.Kotlin 中的協(xié)程是什么?
簡單理解:一般程序會有一個主進程链韭,主進程中可能含有多個線程排霉。而協(xié)程窍株,是線程中的,也就是說一個線程中可能包含多個協(xié)程攻柠,協(xié)程與協(xié)程之間是可以嵌套的球订。
2.有什么作用?
當線程要執(zhí)行可能會阻塞的任務時瑰钮,一般情況下會開啟一個子線程來完成冒滩,如果阻塞任務過多,就需要開啟多個子線程(線程池)浪谴,協(xié)程可以幫助我們完成的是开睡,將可能會阻塞的任務放在線程的協(xié)程中來完成,多個任務就創(chuàng)建多個協(xié)程苟耻。線程直接維持數(shù)據(jù)準確性需要消耗很多資源篇恒,而協(xié)程消耗的會少很多。
注:協(xié)程是可以直接運行在進程中的凶杖,不是一定要依賴于線程胁艰,只不過現(xiàn)在支持協(xié)程的 Kotlin
Python
Go
等語言都會以主線程的方式開啟程序的運行。
總結(jié):通過提升 CPU 利用率官卡,減少線程切換進而提升程序運行效率蝗茁。
3.協(xié)程的特性
- 可控制:協(xié)程能做到可被控制的發(fā)起子任務(協(xié)程的啟動和停止都由代碼控制,不像 java)
- 輕量級:協(xié)程非常小寻咒,占用資源比線程還少
- 語法糖:使多任務或多線程切換不再使用回調(diào)語法
二哮翘、協(xié)程庫
kotlinx.coroutines
compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5"
1.使用 idea 創(chuàng)建 gradle 工程
2.在Kotlin中啟動協(xié)程
- runBlocking: T
- 用于執(zhí)行協(xié)程任務,通常只用于啟動最外層的協(xié)程(線程到協(xié)程的調(diào)度)
- launch: Job
- 用于執(zhí)行協(xié)程任務毛秘,返回的 Job 是一個接口引用
- async/await: Deferred
- 用于執(zhí)行協(xié)程任務饭寺,并得到執(zhí)行結(jié)果
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking
/**
* main=runBlocking
* 表示主線程開始后直接就開啟了一個協(xié)程
* 在協(xié)程中執(zhí)行任務
*/
fun main(args: Array<String>) = runBlocking {
val job = launch {
repeat(10) { I ->
println("掛起中------$I")
//每次循環(huán)阻课,暫停1秒
delay(1000L)
}
}
val job2 = async {
//掛起5秒
delay(5000L)
//使用注解標注此處返回的是 async 的閉包
return@async "我是 async 返回的內(nèi)容"
}
/**
* await 是一個阻塞式方法
* 會將主線程停在這里
* 當 job2 掛起5秒結(jié)束,返回內(nèi)容
* await 接受到內(nèi)容艰匙,主線程才繼續(xù)向下執(zhí)行-->開始等待
*/
println("job2 返回的內(nèi)容:${job2.await()}")
println("主線程開始等待-----")
delay(3000L)
println("主線程等待結(jié)束-----取消launch開啟的協(xié)程")
job.cancel()//協(xié)程的啟動和停止都是代碼可控的
println("主線程執(zhí)行完畢限煞,即將推出-----")
}
三、協(xié)程的啟動參數(shù)
以下是 launch 的參數(shù)列表员凝,runBlocking署驻、async 與 launch 參數(shù)列表是差不多的
- context: CoroutineContext = DefaultDispatcher
- 當前 協(xié)程 的上下文,用于在 協(xié)程 與 協(xié)程 之間參數(shù)傳遞
- 可以用于聲明當前 協(xié)程 在哪一個線程中聲明健霹,以及當前 協(xié)程 被中斷后旺上,在哪一個線程中恢復它
- DefaultDispatcher 就是一個默認的調(diào)度器,當前哪個線程在運行糖埋,就直接取哪個線程
- start: CoroutineStart = CoroutineStart.DEFAULT
- 協(xié)程 的啟動參數(shù)宣吱,表示已哪種方式啟動
- CoroutineStart.DEFAULT 默認的啟動方式,表示當前線程什么時候有空瞳别,就什么時候啟動
- 可選參數(shù):LAZY征候,如果沒有手動調(diào)用 job 對象的 start() 或 join() 方法的話,那么該 協(xié)程 是不會被啟動的
- 可選參數(shù):ATOMIC祟敛,將 協(xié)程 以一個原子性質(zhì)的形式的啟動疤坝,如果聲明此參數(shù),則協(xié)程是不可以 cancel 的
- 可選參數(shù):UNDISPATCHED馆铁,未定義卒煞,通常用于自定義的啟動方式,如果未自定義叼架,則與 DEFAULT 啟動方式一致。
- parent: Job? = null
- 表示在當前 協(xié)程 閉包的外層的 job衣撬,一般情況下使用不到
- block: suspend CoroutineScope.() -> Unit
- 協(xié)程真正要去執(zhí)行的內(nèi)容
四乖订、協(xié)程的語法糖
允許我們使用同步的代碼格式,發(fā)起一次異步的網(wǎng)絡請求
package zyf.com.kotlin_
import android.os.AsyncTask
import kotlinx.coroutines.experimental.CoroutineDispatcher
import kotlinx.coroutines.experimental.Runnable
import kotlin.coroutines.experimental.CoroutineContext
/**
* create by zyf on 2018/9/17 下午4:58
*/
object AndroidCommonPool: CoroutineDispatcher(){
override fun dispatch(context: CoroutineContext, block: Runnable) {
//使用android官方提供的線程池來執(zhí)行任務
AsyncTask.THREAD_POOL_EXECUTOR.execute(block)
}
}
package zyf.com.kotlin_
import android.widget.TextView
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking
import okhttp3.OkHttpClient
import okhttp3.Request
/**
* create by zyf on 2018/9/17 下午4:46
*/
private val mOkHttpClient= OkHttpClient()
private val mRequest=Request.Builder().url("https://www.baidu.com").get().build()
fun ktGet(textView: TextView) = runBlocking{
launch(UI) {
//傳入的AndroidCommonPool表示 async 開啟的這個協(xié)程具练,允許在 AndroidCommonPool 提供的線程中
textView.text = async(AndroidCommonPool) {
mOkHttpClient.newCall(mRequest).execute().body()?.string()
}.await()
}
}
package zyf.com.kotlin_
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun java(v:View){
}
fun kotlin(v:View){
ktGet(showTv)
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/showTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/javaBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Java獲取網(wǎng)絡數(shù)據(jù)"/>
<Button
android:id="@+id/kotlinBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kotlin獲取網(wǎng)絡數(shù)據(jù)"
android:onClick="kotlin"/>
<Button
android:id="@+id/cleanBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清除"/>
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>