Kotlin 线程管理-关键函数join,yield函数介绍
1. 介绍
主要介绍Kotlin
中线程的几种状态的管理例如等待,让步和停止。
而这几种管理状态,主要就是基于join
,yield
等函数。下面让我们详细了解一下如何使用吧。
2. 线程等待-join函数
当使用Thread对象调用
join`函数,会使当前的线程进入阻塞状态。这个时候如果线程结束或等待时间超时当前线程就会回到就绪状态。
线程的几种状态可以通过我的这篇文章了解:Kotlin 线程知识详解 (zinyan.com)
而join函数主要有两种使用方式:
- join():等待线程结束
- join(milliis:Long) :等待线程结束的时间最长为millis毫秒。如果我们填写0,意味着线程将一直等待下去。
使用示例如下所示:
import kotlin.concurrent.thread
var value = 0
fun main(args: Array<String>) {
println("主线程 main")
val t1= thread {
println("子线程 t1")
for(i in 1..10){
println("t1 子线程输出:$i")
value++
}
println("子线程 t1 结束")
}
t1.join()
println("value = $value")
println("主线程main结束")
}
//输出结果
主线程 main
子线程 t1
t1 子线程输出:1
t1 子线程输出:2
t1 子线程输出:3
t1 子线程输出:4
t1 子线程输出:5
t1 子线程输出:6
t1 子线程输出:7
t1 子线程输出:8
t1 子线程输出:9
t1 子线程输出:10
子线程 t1 结束
value = 10
主线程main结束
我们如果在上面的示例中,去掉t1.join()
那么主线程还会等待t1执行完毕么?
如果t1
线程不执行join
。那么主线程就不会等待它的执行,主线程会先执行完毕。输出结果会变成如下所示:
value = 0
主线程main结束
子线程 t1
t1 子线程输出:1
t1 子线程输出:2
t1 子线程输出:3
t1 子线程输出:4
t1 子线程输出:5
t1 子线程输出:6
t1 子线程输出:7
t1 子线程输出:8
t1 子线程输出:9
t1 子线程输出:10
子线程 t1 结束
所以,我们在调用join
函数的时候,并不是指该thread
等待,而是在告诉当前运行的线程等待,等子线程执行完毕后再执行。
不只是主线程下可以调用join,在其他线程中也是可以调用的,join的主要使用场景就是一个线程依赖另外一个线程的运行结果,这样我们就可以使用join函数让依赖的线程结束后得到它的结果并带入当前线程进行下一步运行。
3. 线程挂起-yield函数
我们在Thread
类中还可以调用一个yield
函数使当前线程给其他线程让步。这个和上面的join
不一样。它类似于java
中常见的sleep
函数,让当前线程放弃cpu的使用权,进入暂停状态。但是有别与sleep
会让线程进入休眠,给其他线程运行的机会,无论线程优先级高低都会有机会运行。而yield
函数暂停的线程只会给相同优先级或更高优先级线程机会,并不会给低于它的优先级的线程运行的机会。
下面让我们通过实例代码进行了解一下它的运行逻辑。示例:
import java.lang.Thread.currentThread
import java.lang.Thread.yield
import kotlin.concurrent.thread
fun run() {
for (i in 1..3) {
println("线程:${currentThread().name}--执行 $i 次运行")
yield()
}
println("线程:${currentThread().name} 执行完毕")
}
fun main(args: Array<String>) {
//创建一个默认名称的子线程,并执行
thread {
run()//执行线程
}
//创建一个名称为zinyan的子线程并执行。
thread(name = "zinyan") {
run()
}
}
//输出
线程:Thread-0--执行 1 次运行
线程:Thread-0--执行 2 次运行
线程:Thread-0--执行 3 次运行
线程:Thread-0 执行完毕
线程:zinyan--执行 1 次运行
线程:zinyan--执行 2 次运行
线程:zinyan--执行 3 次运行
线程:zinyan 执行完毕
我们要注意,yield函数有两个包都提供了。一个是java.lang.Thread.yield
,另外一个是 kotlinx.coroutines.yield
。
后面的这个是协程库提供的,必须在协程中才能使用。我们一般情况下大多数使用的sleep函数,在实际开发中很少使用yield,因为它不能控制挂起时间。而现在kotlin中大家对线程的使用更多的通过协程来使用。
4. 线程停止-可控制
我们的线程体运行结束后,线程就会进入死亡状态。Kotlin 线程知识详解 (zinyan.com);这篇基础介绍中有详细描述哦。
但有时候我们需要线程一直重复执行。只有满足特定指令时,才会关闭。
例如,我们需要一个线程,每30秒执行一次特定事件。只有得到关闭指令时才停止重复触发。
示例:
import kotlin.concurrent.thread
var command = ""
fun main(args: Array<String>) {
val tr = thread {
while (command != "zinyan") {
println("线程要执行的事情")
Thread.sleep(30000)//休眠30秒
}
println("线程执行结束")
}
command = readLine()!! //用来接收控制台的输入,添加!! 是为了标注不能输入空
}
//输出
线程要执行的事情
zinyan
线程执行结束
readLine
这个和java标准的System.in一样,能够从控制台等获取键盘输入。
最后,建议大家使用Thread的时候,不要使用系统提供的stop函数。因为该函数有时候会引发严重的系统故障类似的还有suspend和resume函数。建议大家要停止线程,可以采用控制变量的方法让线程体运行结束。
评论区