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.
-
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. ↩