程序员社区

Kotlin协程第一个示例剖析

Kotlin协程第一个示例剖析

Gradle工程

这里新建一个Gradle工程

默认的gradle的配置如下

plugins {
    id 'java'
    id 'org.jetbrains.kotlin.jvm'
}

group 'org.example'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'//指定Kotlin的基础依赖包和协程相关的依赖包
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

test {
    useJUnitPlatform()
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

示例剖析

fun main() {
    //CoroutineScope.launch{}:
    //CoroutineScope.launch{}是最常用的Coroutine builders,不阻塞当前线程,在后台创建一个新协程,也可以指定协程调度器。
    //GlobalScope 协程构建器
    GlobalScope.launch {
        delay(1000)//此时不会阻塞线程,当指定的时间过后协程会恢复执行
        println("Kotlin Coroutines")
    }

    println("Hello")

    Thread.sleep(2000)

    println("World")
}

RUN> ??????

Hello
Kotlin Coroutines
World

Process finished with exit code 0

而看一下GlobalScope这个类,就是它的实现类

public object GlobalScope : CoroutineScope {
    /**
     * Returns [EmptyCoroutineContext].
     */
    override val coroutineContext: CoroutineContext
        get() = EmptyCoroutineContext
}

CoroutineScope.launch{}是最常用的Coroutine builders不阻塞当前线程,在后台创建一个新协程,也可以指定协程调度器。

Kotlin协程第一个示例剖析插图
image-20210611104659135

public suspend fun delay(timeMillis: Long)

/**
 * Delays coroutine for a given time without blocking a thread and resumes it after a specified time.
 *
 * This suspending function is cancellable.
 * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
 * immediately resumes with [CancellationException].
 * There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
 * suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
 *
 * If you want to delay forever (until cancellation), consider using [awaitCancellation] instead.
 *
 * Note that delay can be used in [select] invocation with [onTimeout][SelectBuilder.onTimeout] clause.
 *
 * Implementation note: how exactly time is tracked is an implementation detail of [CoroutineDispatcher] in the context.
 * @param timeMillis time in milliseconds.
 */
public suspend fun delay(timeMillis: Long) {
    if (timeMillis <= 0) return // don't delay
    return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
        // if timeMillis == Long.MAX_VALUE then just wait forever like awaitCancellation, don't schedule.
        if (timeMillis < Long.MAX_VALUE) {
            cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)
        }
    }
}
Delays coroutine for a given time without blocking a thread and resumes it after a specified time.
会延迟协程指定的时间;但是此时并不会阻塞线程,而当指定的时间过后则协程又会恢复执行
Kotlin协程第一个示例剖析插图1
image-20210611105043253

修改示例

Thread.sleep(500)

fun main() {
    //CoroutineScope.launch{}:
    //CoroutineScope.launch{}是最常用的Coroutine builders,不阻塞当前线程,在后台创建一个新协程,也可以指定协程调度器。
    //GlobalScope 协程构建器
    GlobalScope.launch {
        delay(1000)//此时不会阻塞线程,当指定的时间过后协程会恢复执行
        println("Kotlin Coroutines")
    }

    println("Hello")

    Thread.sleep(500)//修改点

    println("World")
}

RUN> ??????

Hello
World

居然协程都木有输出,这是因为协程是依附于线程的,当线程都退出了,当然协程也不会执行了嘛,这点可以清楚的体会到协程的一个角色。

Kotlin线程使用技巧:

对于上面协程的效果其实可以用纯线程的方式来实现,这里来学习一下在Koltin中使用线程的一个标准姿势,跟Java还是有很大的区别的,如下:

import kotlin.concurrent.thread

fun main() {

    thread {
        Thread.sleep(1000)
        println("Kotlin Coroutines")
    }

    println("Hello")

    Thread.sleep(2000)

    println("World")

RUN> ??????

Hello
Kotlin Coroutines
World

Process finished with exit code 0

理解Kotlin的这种创建线程的方式,先看一下这个thread是怎么定义的

/**
 * Creates a thread that runs the specified [block] of code.
 *
 * @param start if `true`, the thread is immediately started.
 * @param isDaemon if `true`, the thread is created as a daemon thread. The Java Virtual Machine exits when
 * the only threads running are all daemon threads.
 * @param contextClassLoader the class loader to use for loading classes and resources in this thread.
 * @param name the name of the thread.
 * @param priority the priority of the thread.
 */
public fun thread(
    start: Boolean = true,
    isDaemon: Boolean = false,
    contextClassLoader: ClassLoader? = null,
    name: String? = null,
    priority: Int = -1,
    block: () -> Unit
): Thread {
    val thread = object : Thread() {
        public override fun run() {
            block()
        }
    }
    if (isDaemon)
        thread.isDaemon = true
    if (priority > 0)
        thread.priority = priority
    if (name != null)
        thread.name = name
    if (contextClassLoader != null)
        thread.contextClassLoader = contextClassLoader
    if (start)
        thread.start()
    return thread
}

居然是一个函数,该函数返回的是一个Thread对象

其中返回的Thread是为Java的

Kotlin协程第一个示例剖析插图2
image-20210611105605984
thread {
        Thread.sleep(1000)
        println("Kotlin Coroutines")
    }

使用了Kotlin的尾随闭包形式,大括号内的为block: () -> Unit的函数体

为啥这样传递了之后我们的线程中的代码就能得到正常执行呢?

Creates a thread that runs the specified [block] of code. 创建一个线程并且运行所指定的代码块。

start - if true, the thread is immediately started. 如果它为真,该线程则会立马start,也就是开始执行嘛

Kotlin协程第一个示例剖析插图3
image-20210611110032722

isDaemon - if true, the thread is created as a daemon thread. The Java Virtual Machine exits when the only threads running are all daemon threads.

如果为true,则该线程 就会被创建为一个守护线程,而对于守护线程,如果所有正在运行的线程都是守护线程的话则JVM会退出

contextClassLoader - the class loader to use for loading classes and resources in this thread

类加载器用来加载这个线程的类和资源

再来看一下此方法的具体实现,就知道为啥这个方法有这样创建线程的功效了:

Kotlin协程第一个示例剖析插图4
image-20210611110524042

修改代码

fun main() {

    //我们手动的来将start参数置为false,看下是否线程中的代码块就不会被执行了:
    thread(start = false) {
        Thread.sleep(1000)
        println("Kotlin Coroutines")
    }

    println("Hello")

    Thread.sleep(2000)

    println("World")
}

RUN > ??????

Hello
World

Process finished with exit code 0

我们也可以以Java的思路将其手动启动

fun main() {

    val t = thread(start = false) {
        Thread.sleep(1000)
        println("Kotlin Coroutines")
    }
    t.start()

    println("Hello")

    Thread.sleep(2000)

    println("World")
}

RUN>

Hello
Kotlin Coroutines
World

Process finished with exit code 0

但是!!!这不是一个正常使用Kotlin的姿势,如果用Java的思维来使用Kotlin这种是不对的,需要适应新的写法

赞(0) 打赏
未经允许不得转载:IDEA激活码 » Kotlin协程第一个示例剖析

一个分享Java & Python知识的社区