学习笔记-kotlin(7)

目录

协程

1.Thread.sleep来阻塞

2.runBlocking阻塞主线程

 3.join来阻塞

4.runBlocking中阻塞(2)

5.作用域构建器

协程

        首先配置,在build.gradle中 配置:

plugins {
    id 'java-library'
    id 'kotlin'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
}

dependencies {
    implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3'
}

        根据官方文档:协程是一个轻量级的线程框架(API)。为什么不直接使用java线程? 因为回调太多。

        开始使用

1.Thread.sleep来阻塞

fun main() {
    GlobalScope.launch {    //在后台启动一个新的协程并继续
        delay(1000) //--挂起函数,不会造成阻塞,但会挂起协程,只能使用在协程中
        println("World!")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    println("Hello,")
    println("ThreadName : ${Thread.currentThread().name}")
    //协程已在等待时主线程还在继续,阻塞主线程2秒来保证jvm存活
    //如果不睡眠,主线程走完就死了,协程也就没了
    Thread.sleep(2000)  //阻塞主线程2秒 保证其jvm的存活
}

运行结果:Hello,
                ThreadName : main
                World!
                ThreadName : DefaultDispatcher-worker-1

 如果我们把sleep去了,运行结果是:Hello,
                                                            ThreadName : main

看运行结果可以看出GlobalScope是创建了一个线程,所以我们可以使用之前的线程打到同样的效果:

fun main() {
    thread{
        Thread.sleep(1000)
        println("World!")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    println("Hello,")
    println("ThreadName : ${Thread.currentThread().name}")
}

运行结果:Hello,
                ThreadName : main
                World!
                ThreadName : Thread-0

使用thread,我们外部就可以不用sleep了。

2.runBlocking阻塞主线程

fun main() {
    GlobalScope.launch {
        delay(1000)
        println("World!")
        println("ThreadName GlobalScope: ${Thread.currentThread().name}")
    }

    println("Hello,")
    println("ThreadName : ${Thread.currentThread().name}")

//    这个表达式阻塞了主线程,我们延迟2秒来保证jvm的存活
    runBlocking {
        delay(2000)
        println("ThreadName runBlocking : ${Thread.currentThread().name}")
    }
}

运行结果:Hello,
                ThreadName : main
                World!
                ThreadName GlobalScope: DefaultDispatcher-worker-1
                ThreadName runBlocking: main

我们可以换一种简洁写法:

//把主线程包装成了一个kotlin的协程
fun main() = runBlocking<Unit> {//开始执行主协程
    GlobalScope.launch {
        delay(1000)
        println("World!")
        println("ThreadName GlobalScope: ${Thread.currentThread().name}")
    }
    println("Hello,")
    println("ThreadName hello: ${Thread.currentThread().name}")

    delay(2000)
    println("ThreadName finally: ${Thread.currentThread().name}")
}

 运行结果:Hello,
                ThreadName hello: main
                World!
                ThreadName GlobalScope: DefaultDispatcher-worker-1
                ThreadName finally: main

 3.join来阻塞

fun main() = runBlocking<Unit> {//开始执行主协程
    val job = GlobalScope.launch {
        delay(1000)
        println("World!")
        println("ThreadName : ${Thread.currentThread().name}")
    }
    println("Hello,")
    println("ThreadName : ${Thread.currentThread().name}    hello")

    job.join()  //等待直到job这个子协程结束,才往下走。  是属于阻塞
    println("complete")
}

运行结果:Hello,
                ThreadName : main    hello
                World!
                ThreadName : DefaultDispatcher-worker-2
                complete

4.runBlocking中阻塞(2)

        我们可以在执行操作所在的指定作用域内启动协程,而不是像通常使用GlobalScope那样启动。包括runBlocking在内的每个协程构建器都将CoroutineScope的实例添加到其代码块所在的作用域中。可以在这个作用域中启动协程,无需显式join,因为外部协程(示例中的runBlocking)。直到在其作用域中启动的所有协程都执行完毕后才会结束。

fun main() = runBlocking<Unit> {
    launch {
        delay(2000L)
        println("World!")
        println("ThreadName launch内的: ${Thread.currentThread().name}")
    }
    println("Hello,")
    println("ThreadName launch之外的: ${Thread.currentThread().name} ")
}

输出结果:Hello,

                 ThreadName launch之外的: main

                 World!

                 ThreadName launch内的: main

5.作用域构建器

        除了由不同的构建器提供协程作用域之外,还可以使用coroutineScope构建器声明自己的作用域。它会创建一个协程作用域且在所有已启动子协程执行完毕之前不会结束,遇到子协程(coroutineScope),不执行完子协程不会继续后面的代码执行

fun main() = runBlocking<Unit> {
    coroutineScope {
        launch {
            delay(2000L)
            println("World!")
            println("ThreadName launch内的: ${Thread.currentThread().name}")
        }
    }
    println("Hello,")
    println("ThreadName launch之外的: ${Thread.currentThread().name} ")
}

输出结果:World!

                  ThreadName launch内的: main

                  Hello,

                  ThreadName launch之外的: main

        这个示例的运行结果就比较明显,在runBlocking中的coroutineScope子协程运行完毕后,才会接着走下去(运行下去) 。下面我们来一个更明显的示例来看看:

fun main() = runBlocking<Unit> {
    launch {
        delay(200L)
        println("Task from 200L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    coroutineScope {
        launch {
            delay(500L)
            println("Task from 500L")
            println("ThreadName : ${Thread.currentThread().name}")
        }
        delay(100L)
        println("Task from 100L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    GlobalScope.launch {
        delay(50L)
        println("Task from 50L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    println("Coroutine scope is over")
    println("ThreadName : ${Thread.currentThread().name}")
}

运行结果:Task from 100L
                  ThreadName : main
                  Task from 200L
                  ThreadName : main
                  Task from 500L
                  ThreadName : main
                  Coroutine scope is over
                  ThreadName : main

        运行结果我们就会有疑问了,为什么不会先输出 is over或者50L的呢?因为我们中间有使用一个子协程coroutineScope,所以要等待coroutineScope运行完毕之后才会执行后边的代码,所以按照lauchcoroutineScope中的delay挂起时间就是先输出100L,200L,500L。coroutineScope结束后没有执行50L的原因是咱们这篇的第一点,在主线程执行结束后,jvm没了,协程自然也就没了。所以就没有执行。如果我们把GlobalScope换成lauch或者再来一个子协程coroutineScope都是会输出50L的,但是运行时序不同,lauch的运行结果会先输出over在输出50L,coroutineScope则是先50L。上代码和运行结果把,比较方便理解:

lauch:

fun main() = runBlocking<Unit> {
    launch {
        delay(200L)
        println("Task from 200L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    coroutineScope {
        launch {
            delay(500L)
            println("Task from 500L")
            println("ThreadName : ${Thread.currentThread().name}")
        }
        delay(100L)
        println("Task from 100L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    launch {
        delay(50L)
        println("Task from 50L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    println("Coroutine scope is over")
    println("ThreadName : ${Thread.currentThread().name}")
}

运行结果:Task from 100L
                  ThreadName : main
                  Task from 200L
                  ThreadName : main
                  Task from 500L
                  ThreadName : main
                  Coroutine scope is over
                  ThreadName : main
                  Task from 50L
                  ThreadName : main

coroutineScope:

fun main() = runBlocking<Unit> {
    launch {
        delay(200L)
        println("Task from 200L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    coroutineScope {
        launch {
            delay(500L)
            println("Task from 500L")
            println("ThreadName : ${Thread.currentThread().name}")
        }
        delay(100L)
        println("Task from 100L")
        println("ThreadName : ${Thread.currentThread().name}")
    }

    coroutineScope{
        launch {
            delay(50L)
            println("Task from 50L")
            println("ThreadName : ${Thread.currentThread().name}")
        }
    }
    
    println("Coroutine scope is over")
    println("ThreadName : ${Thread.currentThread().name}")
}

运行结果:Task from 100L
                  ThreadName : main
                  Task from 200L
                  ThreadName : main
                  Task from 500L
                  ThreadName : main
                  Task from 50L
                  ThreadName : main
                  Coroutine scope is over
                  ThreadName : main

        最后这两个例子可以说是串起了这篇的大多知识点。 共勉,一起加油

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值