Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kotlin (kotlin.concurrent.thread)

Por baixo dos panos, Kotlin usa a mesma java.lang.Thread da JVM. O que muda é a ergonomia: a função thread() do pacote kotlin.concurrent cria, configura e inicia a thread numa chamada só.

import kotlin.concurrent.thread

fun main() {
    val t = thread {
        println("Hello from thread!")
    }
    t.join()
}

Código 4-17: Criando uma thread em Kotlin.

thread() recebe uma lambda, cria a java.lang.Thread, chama start() e retorna o objeto. Como é a mesma JVM, a mesma regra se aplica: o programa não encerra enquanto threads não-daemon estiverem rodando. Para marcar como daemon, basta isDaemon = true.

Captura de variáveis

Em Java, lambdas só capturam variáveis effectively final. Kotlin não tem essa restrição: lambdas capturam qualquer variável do escopo externo, inclusive var:

import kotlin.concurrent.thread

fun main() {
    var counter = 0
    val t = thread { counter++ }
    t.join()
    println("counter = $counter")
}

Com uma thread só, funciona. Mas com várias threads incrementando counter ao mesmo tempo, seria uma race condition. E o compilador não dá nenhum sinal de alerta. Não tem erro de compilação, não tem warning, não tem nenhuma indicação de que algo pode dar errado. Essa liberdade coloca a responsabilidade inteira nas costas do programador.

Múltiplas threads

import kotlin.concurrent.thread

fun main() {
    val threads = (0 until 10).map { i ->
        thread { println("Hello from thread $i!") }
    }
    threads.forEach { it.join() }
}

Código 4-18: Criando múltiplas threads em Kotlin.

$ kotlinc main.kt -include-runtime -d main.jar && java -jar main.jar
Hello from thread 1!
Hello from thread 0!
Hello from thread 3!
Hello from thread 2!
Hello from thread 5!
Hello from thread 4!
Hello from thread 6!
Hello from thread 7!
Hello from thread 9!
Hello from thread 8!

O (0 until 10).map { ... } cria as 10 threads e coleta numa lista. forEach faz o join de cada uma.

Retornando valores

Como a lambda pode capturar e modificar variáveis do escopo externo, retornar um valor de uma thread é direto:

import kotlin.concurrent.thread

fun main() {
    var answer = 0
    val t = thread { answer = 7 * 7 }
    t.join()
    println("7² = $answer")
}

Código 4-19: Retornando um valor de uma thread em Kotlin.

A lambda modifica answer direto, e após o join() o valor está lá1.


  1. Na prática, boa parte do código Kotlin concorrente usa coroutines (kotlinx.coroutines) ao invés de threads diretamente. Threads do SO continuam sendo o mecanismo subjacente, mas coroutines adicionam structured concurrency e cancelamento cooperativo. ↩