持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
前言
线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。 一个进程中可以并发多个线程,每条线程并行执行不同的任务。每个线程都会分配一个私有内存区域,该区域主要用于在执行过程中存储方法、局部变量和参数。一旦线程终止私有内存区将会被销毁。
基础
Java/Kotlin 有一个名为的类Thread
,主要是用于在主线程之外执行代码逻辑。当我们要执行于非主线程代码时,我们一般自定义Thread
类,步骤如下:
- 创建一个继承自
Thread
的子类 - 重写父类的
run
方法 - 在需要调用的地方新建一个子类的实例并调用它的
start()
方法
才艺展示:
class NewThread : Thread() {
// 重写run方法
override fun run() {
// 这里执行非主线程逻辑
}
}
fun functionA() {
val thread = NewThread()
// 调用`start()`方法
thread.start()
}
需要注意的是当实例化的NewThread
线程完成了run
交代的任务之后,该线程就会被无情的销毁。假设业务并不希望该线程被销毁,而是等待执行下一个交代的任务,那么这时候我们想到了可能需要一个任务队列来协助我们的线程持续的完成任务。
工作线程
工作线程有一个任务队列。当线程完成其当前任务时,它会从队列中选择下一个任务并执行它。当任务队列为空时,线程会一直等待,直到有任务可以执行。
我们要做的是以三种不同的方式实现一个工作线程。从最繁琐到最优雅!
自定义工作队列版本
为了从头开始实现工作线程,还是继承Thread
类,步骤如下:
- 在
run
方法内部实现一个无限循环函数体 - 通过
execute
方法,并创建一个队列变量taskQueue
用来存储、跟踪要执行的任务 - 在无限循环中,我们从队列中获取下一个任务并执行它
- 提供
quit
方法来终止无限循环,这样我们就可以在完成后停止工作线程。
才艺展示:
class CustomTaskThread : Thread() {
private val isAlive = AtomicBoolean(true)
// 任务队列
private val taskQueue = ConcurrentLinkedQueue<Runnable>()
init {
start()
}
override fun run() {
// 线程启动开始无限循环
while (isAlive.get()) {
if (taskQueue.isNotEmpty()) {
val task: Runnable = taskQueue.poll()
task.run()
}
}
}
// 提交执行
fun execute(block: () -> Unit) {
taskQueue.add(Runnable { block() })
}
// 终止执行
fun quit() {
isAlive.set(false)
}
}
fun functionA() {
val thread = CustomTaskThread()
thread.execute {
// 代码逻辑
}
thread.execute {
// 代码逻辑
}
thread.quit()
}
我们使用这种方式实现的线程,但它有两个问题:
- 当没有任务执行时,
run
方法内部的while循环会不断检查isAlive
。这样会十分浪费CPU
资源 - 我们需要非常仔细的管理任务队列这样的事情。
下一篇我们将了解其他方式