🔏
Tech
  • 🟢App aspects
    • Software architecture
      • Caching
      • Anti-patterns
      • System X-ability
      • Coupling
      • Event driven architecture
        • Command Query Responsibility Segregation (CQRS)
        • Change Data Capture (CDC)
      • Distributed transactions
      • App dev notes
        • Architecture MVP
      • TEMP. Check list
      • Hexagonal arch
      • Communication
        • REST vs messaging
        • gRPC
        • WebSocket
      • Load balancers
      • Storage limits
      • Event storming
    • Authentication
    • Deployment strategy
  • Databases
    • Classification
    • DB migration tools
    • PostreSQL
    • Decision guidance
    • Index
      • Hash indexes
      • SSTable, LSM-Trees
      • B-Tree
      • Engines, internals
    • Performance
  • System design
    • Interview preparation
      • Plan
        • Instagram
        • Tinder
        • Digital wallet
        • Dropbox
        • Live video streaming
        • Uber
        • Whatsup
        • Tiktok
        • Twitter
        • Proximity service
    • Algorithms
    • Acronyms
  • 🟢Programming languages
    • Java
      • Features
        • Field hiding
        • HashCode() and Equals()
        • Reference types
        • Pass by value
        • Atomic variables
      • Types
      • IO / NIO
        • Java NIO
          • Buffer
          • Channel
        • Java IO: Streams
          • Input streams
            • BufferedInputStream
            • DataInputStream
            • ObjectInputStream
            • FilterInputStream
            • ByteArrayInputStream
        • Java IO: Pipes
        • Java IO: Byte & Char Arrays
        • Java IO: Input Parsing
          • PushbackReader
          • StreamTokenizer
          • LineNumberReader
          • PushbackInputStream
        • System.in, System.out, System.error
        • Java IO: Files
          • FileReader
          • FileWriter
          • FileOutputStream
          • FileInputStream
      • Multithreading
        • Thread liveness
        • False sharing
        • Actor model
        • Singleton
        • Future, CompletableFuture
        • Semaphore
      • Coursera: parallel programming
      • Coursera: concurrent programming
      • Serialization
      • JVM internals
      • Features track
        • Java 8
      • Distributed programming
      • Network
      • Patterns
        • Command
      • Garbage Collectors
        • GC Types
        • How GC works
        • Tools for GC
    • Kotlin
      • Scope functions
      • Inline value classes
      • Coroutines
      • Effective Kotlin
    • Javascript
      • Javascript vs Java
      • TypeScript
    • SQL
      • select for update
    • Python
      • __init.py__
  • OS components
    • Network
      • TCP/IP model
        • IP address in action
      • OSI model
  • 🟢Specifications
    • JAX-RS
    • REST
      • Multi part
  • 🟢Protocols
    • HTTP
    • OAuth 2.0
    • LDAP
    • SAML
  • 🟢Testing
    • Selenium anatomy
    • Testcafe
  • 🟢Tools
    • JDBC
      • Connection pool
    • Gradle
    • vim
    • git
    • IntelliJ Idea
    • Elastic search
    • Docker
    • Terraform
    • CDK
    • Argo CD
      • app-of-app setup
    • OpenTelemetry
    • Prometheus
    • Kafka
      • Consumer lag
  • 🟢CI
    • CircleCi
  • 🟢Platforms
    • AWS
      • VPC
      • EC2
      • RDS
      • S3
      • IAM
      • CloudWatch
      • CloudTrail
      • ELB
      • SNS
      • Route 53
      • CloudFront
      • Athena
      • EKS
    • Kubernetes
      • Networking
      • RBAC
      • Architecture
      • Pod
        • Resources
      • How to try
      • Kubectl
      • Service
      • Tooling
        • ArgoCD
        • Helm
        • Istio
    • GraalVM
    • Node.js
    • Camunda
      • Service tasks
      • Transactions
      • Performance
      • How it executes
  • 🟢Frameworks
    • Hibernate
      • JPA vs Spring Data
    • Micronaut
    • Spring
      • Security
      • JDBC, JPA, Hibernate
      • Transactions
      • Servlet containers, clients
  • 🟢Awesome
    • Нейробиология
    • Backend
      • System design
    • DevOps
    • Data
    • AI
    • Frontend
    • Mobile
    • Testing
    • Mac
    • Books & courses
      • Path: Java Concurrency
    • Algorithms
      • Competitive programming
    • Processes
    • Finance
    • Electronics
  • 🟢Electronics
    • Arduino
    • IoT
  • Artificial intelligence
    • Artificial Intelligence (AI)
  • 🚀Performance
    • BE
  • 📘Computer science
    • Data structures
      • Array
      • String
      • LinkedList
      • Tree
    • Algorithms
      • HowTo algorithms for interview
  • 🕸️Web dev (Frontend)
    • Trends
    • Web (to change)
  • 📈Data science
    • Time series
Powered by GitBook
On this page
  • Context
  • Suspend function
  • Testing of suspend function
  • Builders
  • Launch
  • runBlocking
  • async
  • Structured concurrency
  • Control
  • Join
  • Cancel

Was this helpful?

  1. Programming languages
  2. Kotlin

Coroutines

Context

Coroutines have to be run inside a context.

Suspend function

Suspend functions make sense to start only from coroutine (compilation requirements). And some functions (e.g. delay()) are making sense only inside of suspend functions.

Suspend function can be called from

  • another suspend function

  • from coroutine (This is the way actually to start a "first" suspend function)

Do not use blocking code (e.g. Thread.sleep()) in coroutine

Testing of suspend function

@Test
fun theTest() = runBlocking { // test should become a coroutine to be able to call suspend function
    doWork()    // assuming that doWork is a suspend function
    //assert bla
}

Builders

Launch

Launch creates a coroutine and submit it to the separate thread, main thread will not wait until the coroutine is finished.

launch { 
    delay(1000) // non blocking the thread, it suspends the courutine
    println("")
}

runBlocking

This can be useful to use in tests (to make test a coroutine to be able to invoke suspend function in the test).

runBlocking is used as a bridge between regular and suspending functions, or between the blocking and non-blocking worlds. It works as an adaptor for starting the top-level main coroutine. It is intended primarily to be used in main() functions and tests.

runBlocking {        // main thread will wait until this coroutine is finished
    delay(1500)
}

async

async starts a new coroutine and returns a Deferred object. Deferred represents a concept known by other names such as Future or Promise. It stores a computation, but it defers the moment you get the final result; it promises the result sometime in the future.

The main difference between async and launch is that launch is used to start a computation that isn't expected to return a specific result. launch returns a Job that represents the coroutine. It is possible to wait until it completes by calling Job.join().

Deferred is a generic type that extends Job. An async call can return a Deferred<Int> or a Deferred<CustomType>, depending on what the lambda returns (the last expression inside the lambda is the result).

To get the result of a coroutine, you can call await() on the Deferred instance. While waiting for the result, the coroutine that this await() is called from is suspended:

import kotlinx.coroutines.*

fun main() = runBlocking {
    val deferred: Deferred<Int> = async {
        loadData()
    }
    println("waiting...")
    println(deferred.await())
}

suspend fun loadData(): Int {
    println("loading...")
    delay(1000L)
    println("loaded!")
    return 42
}

Structured concurrency

The coroutine scope is responsible for the structure and parent-child relationships between different coroutines. New coroutines usually need to be started inside a scope.

When launch, async, or runBlocking are used to start a new coroutine, they automatically create the corresponding scope. All of these functions take a lambda with a receiver as an argument, and CoroutineScope is the implicit receiver type:

launch { /* this: CoroutineScope */ }
import kotlinx.coroutines.*

fun main() = runBlocking { /* this: CoroutineScope */
    launch { /* ... */ }
    // the same as:
    this.launch { /* ... */ }
}

Control

Join

Similar to joining a thread. The calling thread blocks until coroutine is finished.

Launch returns Job, which has join method. We can also check is coroutine is finished.

val job = launch { 
    println("")
}
job.join() // join is a suspend function

Cancel

In order to be cancellable coroutine should be able to check for cancellation.

E.g. delay() function knows how to cancel.

fun main() = runBlocking {
     val job = launch {
         repeat(1000) {
            delay(1)          // delay knows how to cancel, so cancellation will work
            print(".")
         }
    }
    delay(15)
    job.cancelAndJoin()
    print("Done")
}
fun main() = runBlocking {
     val job = launch {
         repeat(1000) {
            Thread.sleep(1) // this function does not know how to cancel, so cancellation will not work
            print(".")
         }
    }
    delay(15)
    job.cancelAndJoin()
    print("Done")
}

It is possible to check the status itself (it did not work on my machine, but I took it from the course)

fun main() = runBlocking {
     val job = launch {
         repeat(1000) {
             if (!isActive) throw CancellationException()
             sleep(10)
             print(".")
         }
    }
    delay(200)
    job.cancelAndJoin()
    print("Done")
}
PreviousInline value classesNextEffective Kotlin

Last updated 3 months ago

Was this helpful?

🟢