← Назад к вопросам
Какие знаешь инструменты для работы с многопоточностью в Kotlin?
2.0 Middle🔥 211 комментариев
#Kotlin основы#Многопоточность и асинхронность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие знаешь инструменты для работы с многопоточностью в Kotlin?
В Kotlin есть несколько инструментов для работы с многопоточностью и асинхронностью. Расскажу про основные.
1. Thread (самый простой, но редко нужен)
// Создать и запустить поток
Thread {
println("Running in thread: ${Thread.currentThread().name}")
Thread.sleep(1000)
println("Done")
}.start()
// С именем
thread(name = "MyThread") {
println("Custom thread")
}
Использование: крайне редко, только для простых случаев.
Проблема: каждый поток занимает 1MB памяти, нельзя создать 10000 потоков.
2. Coroutines (основной инструмент)
// launch: не возвращает результат
launch {
val data = api.fetch()
updateUI(data)
}
// async: возвращает результат
val result = async {
api.fetch()
}.await()
// runBlocking: блокирует текущий поток
runBlocking {
api.fetch()
}
// withContext: переключить контекст
val result = withContext(Dispatchers.IO) {
api.fetch() // На IO потоке
}
Преимущества:
- Легковесные (миллионы корутин на одном приложении)
- Простой синтаксис
- Structured concurrency (управление жизненным циклом)
3. Dispatcher'ы (выбор потока)
// Main поток (UI обновления)
launch(Dispatchers.Main) {
updateUI()
}
// IO поток (сетевые запросы, файлы, БД)
launch(Dispatchers.IO) {
val data = database.getUser()
val response = api.fetch()
}
// Default (CPU-intensive задачи)
launch(Dispatchers.Default) {
val result = expensiveCalculation()
}
// Unlimited (не рекомендуется в 99% случаев)
launch(Dispatchers.Unconfined) {
// Опасно!
}
4. Flow (реактивный поток данных)
// Создать Flow
fun getNumbers(): Flow<Int> = flow {
for (i in 1..5) {
delay(100)
emit(i) // Отправить значение
}
}
// Использовать
getNumbers()
.filter { it > 2 }
.map { it * 2 }
.collect { println(it) }
// С StateFlow (LiveData на стероидах)
val state = MutableStateFlow(0)
launch {
state.collect { value ->
println("State: $value")
}
}
state.value = 42
5. Mutex и Synchronization
// Mutex: мьютекс для синхронизации
val mutex = Mutex()
var count = 0
launch {
mutex.withLock {
count++ // Безопасно
}
}
// Semaphore: ограничить количество одновременных операций
val semaphore = Semaphore(3)
repeat(10) {
launch {
semaphore.acquire()
try {
println("Task $it")
delay(100)
} finally {
semaphore.release()
}
}
}
6. Channel (общая очередь между корутинами)
// Создать канал
val channel = Channel<Int>()
// Отправитель
launch {
channel.send(1)
channel.send(2)
channel.close()
}
// Получатель
launch {
for (value in channel) {
println(value)
}
}
// Пример: producer-consumer
fun produceNumbers() = produce<Int> {
var x = 1
while (true) {
send(x++)
delay(100)
}
}
launch {
val numbers = produceNumbers()
numbers.consumeEach { println(it) }
}
7. Atomic Variables (потокобезопасные переменные)
import java.util.concurrent.atomic.AtomicInteger
val counter = AtomicInteger(0)
launch {
repeat(100) {
counter.incrementAndGet() // Потокобезопасно
}
}
println(counter.get())
8. ConcurrentCollections (потокобезопасные коллекции)
import java.util.concurrent.ConcurrentHashMap
val map = ConcurrentHashMap<String, String>()
launch {
map["key"] = "value" // Потокобезопасно
}
launch {
println(map["key"])
}
9. RxJava (устаревает, но еще используется)
// Observable
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value ->
println(value)
}
// Subject (like Channel)
val subject = PublishSubject.create<Int>()
subject.onNext(1)
subject.onNext(2)
subject.subscribe { println(it) }
10. Comparison таблица
| Инструмент | Сложность | Потребление памяти | Использование |
|---|---|---|---|
| Thread | Средняя | Много (1MB на поток) | Редко |
| Coroutines | Низкая | Мало | ОСНОВНОЕ |
| Flow | Средняя | Нормально | Реактивное программирование |
| Mutex | Средняя | Минимум | Синхронизация |
| Channel | Средняя | Нормально | Общение между корутинами |
| Atomic | Низкая | Минимум | Потокобезопасные переменные |
| RxJava | Высокая | Много | Переходим на Flow |
11. Structured Concurrency (золотой стандарт)
// Иерархия: родитель контролирует детей
val parentJob = Job()
val scope = CoroutineScope(Dispatchers.Main + parentJob)
scope.launch {
launch { /* child 1 */ }
launch { /* child 2 */ }
// Если отменить parentJob, отменятся ВСЕ дети
}
parentJob.cancel() // Отменить ВСЁ
12. Какой инструмент выбрать?
Нужна UI работа (обновление View)?
→ launch(Dispatchers.Main)
Нужен результат?
→ async { }.await()
Потребляю поток данных (от сервера, БД)?
→ Flow + collect
Нужна синхронизация?
→ Mutex.withLock
Одна корутина отправляет, другая получает?
→ Channel
Нужна потокобезопасная переменная?
→ AtomicInteger, ConcurrentHashMap
Сложный реактивный код?
→ Flow (или RxJava если старый проект)
13. Best Practices
✅ Используй Coroutines по умолчанию ✅ Используй viewModelScope в ViewModel ✅ Используй lifecycleScope в Activity/Fragment ✅ Используй Flow для потока данных ✅ Используй Dispatchers правильно (IO для сети/БД) ✅ Используй Structured Concurrency (Job родитель/ребенок)
❌ НЕ используй Thread вручную ❌ НЕ забывай про scope (не утекай корутины) ❌ НЕ вызывай delay() на Main потоке (блокируется) ❌ НЕ используй GlobalScope
Итог
- Coroutines = основной инструмент для асинхронности
- Flow = для реактивного программирования
- Dispatcher'ы = выбор потока (Main, IO, Default)
- Mutex = синхронизация между корутинами
- Channel = общение между корутинами
- Structured Concurrency = управление жизненным циклом
- Забудь про Thread (корутины вместо них)