Thread
, передать им инстансы Runnable
, с нужными задачами в реализации их методов run
, и запустить вызвав thread.start()
. Если в основном потоке нужно дождаться завершения задач – после start()
вызывается метод thread.join()
. Исполнение зависнет на вызове этого метода до тех пор, пока тред не закончит свою задачу и не умрет. Вся работа задач с внешними данными должна быть синхронизирована.Такое ручное создание тредов полезно в учебных целях, но считается плохой практикой в промышленном коде: само создание – дорогостоящая операция, а большое количество случайно созданных потоков может приводить к проблеме голодания (starvation) потоков.
В качестве продвинутой альтернативы используются пуллы потоков – реализации интерфейса
ExecutorService
. Такие сервисы создаются статическими фабричными методами класса Executors
. Они умеют принимать задачи в виде Runnable
- или Callable
-объектов на заранее созданном наборе потоков (собственно, пулле).Кроме самого пулла, экземпляры
ExecutorService
содержат фабрику потоков («инструкцию» как создать тред при необходимости), и коллекцию-очередь задач на исполнение.В ответ на передачу на исполнение
Runnable
или Callable
, сервис возвращает связанный с ним объект типа Future
– хранилище, которое будет заполнено результатом выполнения задачи в будущем. Даже если никакого результата не ожидается, Future
поможет дождаться момента завершения обработки задачи.В Android для асинхронного выполнения используется похожая сущность – Looper.