Каковы ключевые различия в реализации многопоточности между Java и Kotlin?

«Каковы ключевые различия в реализации многопоточности между Java и Kotlin?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основное различие заключается в модели параллелизма: Java использует потоки операционной системы (OS threads), а Kotlin предлагает корутины (coroutines) — легковесные потоки, управляемые средой выполнения.

Java (традиционные потоки):

  • Основаны на классах Thread, ExecutorService, CompletableFuture.
  • Поток ОС — тяжеловесный ресурс. Создание тысяч потоков затратно.
  • Блокирующие операции (например, сетевой вызов) блокируют поток целиком.
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<String> future = executor.submit(() -> {
    // Блокирующий сетевой запрос
    return performNetworkCall();
});

Kotlin (корутины):

  • Основаны на suspend-функциях и конструкциях launch/async.
  • Корутина — легковесная сущность. Можно запускать десятки тысяч корутин.
  • Suspend-функции не блокируют поток, а приостанавливают выполнение корутины, освобождая поток для других задач.
suspend fun fetchData(): String = withContext(Dispatchers.IO) {
    // Приостанавливающий, неблокирующий сетевой запрос
    performNetworkCall()
}
// Вызов в корутине
CoroutineScope(Dispatchers.Main).launch {
    val result = fetchData() // Приостановка здесь не блокирует Main-поток
    updateUI(result)
}

Ключевые отличия:

  1. Ресурсы: Корутины на порядки эффективнее по потреблению памяти, чем потоки ОС.
  2. Парадигма: Kotlin поощряет написание последовательного неблокирующего кода, избегая "callback hell".
  3. Управление: В Kotlin управление диспетчерами (Dispatchers) проще, чем ручная настройка пулов потоков в Java.
  4. Отмена: Корутины имеют встроенную поддержку отмены через иерархию Job.