Работал ли с ExecutorService

Ответ

Да, работал. ExecutorService — это интерфейс из пакета java.util.concurrent, который упрощает управление потоками. Чаще всего использую ThreadPoolExecutor или Executors для создания пула потоков.

Пример:

val executor = Executors.newFixedThreadPool(4)  
executor.submit {  
    // Выполнение задачи в фоне  
    val result = doBackgroundWork()  
    runOnUiThread { updateUI(result) }  
}  
executor.shutdown() // Важно закрывать после использования  

Нюансы:

  • Не забывать вызывать shutdown() или shutdownNow(), иначе потоки могут остаться висеть.
  • Для UI-обновлений после фоновой работы использовать runOnUiThread/Handler.
  • Выбирать подходящий тип пула (Fixed, Cached, SingleThread).

Ответ 18+ 🔞

А, ну это же классика, ёпта! ExecutorService — это ж как раз та штука, чтобы не городить свои велосипеды с Thread. Интерфейс из java.util.concurrent, который всю эту муть с потоками делает человеческой.

Вот смотри, обычно беру ThreadPoolExecutor или, что чаще, фабрику Executors — она сразу готовый пул потоков выдает. Удобно, блядь.

Вот, например, стандартный кусок:

val executor = Executors.newFixedThreadPool(4)  // Четыре работяги в пуле
executor.submit {  
    // Тяжелая работа на заднем плане
    val result = doBackgroundWork()  
    runOnUiThread { updateUI(result) }  // А результат — на главный поток, в UI
}  
executor.shutdown() // А это, сука, ВАЖНО не забыть!

Теперь по нюансам, тут внимательно:

  • Не забывай shutdown()! Это, блядь, самое главное. Если не закрыть, потоки так и будут висеть, как призраки, память жрать. shutdownNow() — если надо резко всех послать и задачи отменить.
  • UI обновлять с умом. После того как в фоне всё сделал, лезть в интерфейс из другого потока — это прямой билет в креш. Только runOnUiThread или Handler. Иначе будет тебе, чувак, CalledFromWrongThreadException — волнение ебать!
  • Выбирай пул по уму. Не тыкай наугад.
    • newFixedThreadPool(4) — стабильная бригада из N работяг. Хорошо для предсказуемой нагрузки.
    • newCachedThreadPool() — ленивый пул. Создаёт потоки по мере надобности, а простаивающие через время убивает. Овердохуища гибкости, но можно и переборщить.
    • newSingleThreadExecutor() — один да один. Все задачи строго по очереди, как в поликлинике. Идеально, когда нужна последовательность, а то от параллельности голова болит.

В общем, штука мощная, но, как и всё в этом мире, требует немного мозгов. Главное — не оставлять за собой бардак, закрывай пулы, и всё будет пизда рулю.