协程
协程简单的来说,就是用户态的线程。
emmm,还是不明白对吧,那想象一个这样的场景,如果在一个单核的机器上有两个线程需要执行,因为一次只能执行一个线程里面的代码,那么就会出现线程切换的情况,一会需要执行一下线程A,一会需要执行一下线程B,线程切换会带来一些开销。
假设两个线程,交替执行,如下图所示
线程会因为Thread.sleep方法而进入阻塞状态(就是什么也不会执行),这样多浪费资源啊。
能不能将代码块打包成一个个小小的可执行片段,由一个统一的分配器去分配到线程上去执行呢,如果我的代码块里要求sleep一会,那么就去执行别的代码块,等会再来执行我呢。
协程就是这样一个东西,我们作为使用者不需要再去考虑创建一个新线程去执行一坨代码,也不需要关心线程怎么管理。我们需要关心的是,我要异步的执行一坨代码,待会我要拿到它的结果,我要异步的执行很多坨代码,待会我要按某种顺序,或者某种逻辑得到它们的结果。
总而言之,协程是用户态的线程,它是在用户态实现的一套机制,可以避免线程切换带来的开销,可以高效的利用线程的资源。
从代码上来讲,也可以更漂亮的写各种异步逻辑。
这里想再讲讲一个概念,阻塞与非阻塞是什么意思
阻塞与非阻塞
简单来说,阻塞就是不执行了,非阻塞就是一直在执行。
比如
Thread.wait() // 阻塞了
// 这里执行不到了
但是,如果
while (true) {
// 一直在运行,没有阻塞
i++;
}
// 这里也执行不到了
runBlocking:连接阻塞与非阻塞的世界
runBlocking是启动新协程的一种方法。
runBlocking启动一个新的协程,并阻塞它的调用线程,直到里面的代码执行完毕。
举个例子
println("aaaaaaaaa ${
Thread.currentThread().name}")
runBlocking {
for (i in 0..10) {
println("$i ${
Thread.currentThread().name}")
delay(100)
}
}
println("bbbbbbbbb ${
Thread.currentThread().name}")
上面代码的输出为:
aaaaaaaaa main
0 main
1 main
2 main
3 main
4 main
5 main
6 main
7 main
8 main
9 main
10 main
bbbbbbbbb main
emmm,这并没有什么稀奇,所有的代码都在主线程执行,按照顺序来,去掉runBlocking也是一样的嘛。
但是,runBlocking可以指定参数,就可以让runBlocking里面的代码在其他线程执行,但同样可以阻塞外部线程。
println("aaaaaaaaa ${
Thread.currentThread().name}")
runBlocking(Dispatchers.IO) {
// 注意这里
for