美文网首页
Kotlin协程第一个示例剖析

Kotlin协程第一个示例剖析

作者: 蒋斌文 | 来源:发表于2021-06-11 11:11 被阅读0次

    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不阻塞当前线程,在后台创建一个新协程,也可以指定协程调度器。

    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.
    会延迟协程指定的时间;但是此时并不会阻塞线程,而当指定的时间过后则协程又会恢复执行
    
    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的

    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,也就是开始执行嘛

    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

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

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

    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这种是不对的,需要适应新的写法

    相关文章

      网友评论

          本文标题:Kotlin协程第一个示例剖析

          本文链接:https://www.haomeiwen.com/subject/smgmeltx.html