- Что такое ExecutorService?
- Руководство по фоновой работе в Android. Часть 3: Executors и EventBus
- Шина событий
- Многопоточность в Java: ExecutorService
- ExecutorService
- ScheduledExecutorService
- Android Executor Tutorial and Examples
- What is ExecutorService?
- ThreadPoolExecutor
- Quick Executor Examples
- 1. Using Executor with Handler
- 2. Example 2
- 3. Example 3
- Example 1: Android ThreadPoolExecutor simple Example
- Step 1: Create Project
- Step 2: Dependencies
- Step 3: Design Layout
- Step 5: Write Code
- Reference
- Example 2 – Android ThreadPoolExecutor
- Step 1: Dependencies
- Step 2: Create MainActivity
- Step 4: Create Layout
- Reference
- Example 3: Kotlin Android ThreadPoolExecutor Example
- Step 1: Create Project
- Step 2: Dependencies
- Step 3: Create layout
- Step 4: Write Code
- Reference
- Oclemy
Что такое ExecutorService?
Честно говоря, вопрос этот не слишком новый. Со времени выхода Java 5 и пакета java.util.concurrent.* прошло более 13 лет, но мне, за всю мою десятилетнюю практику, так ни разу и не пришлось столкнуться с этим зверем. Тем не менее, мне этот вопрос несколько раз задавали на собеседованиях и пришлось знакомиться.
Первое естественно с чего я начал это — Хабр. Но, к сожалению, нашёл здесь только две статьи:
Первая, очевидно, для тех, кто понимает и имеет опыт работы с ExecutorService. Вторая в меня, к сожалению, не вошла. Вроде небольшая и «по делу», но перечитав несколько раз я так и не понял, что же такое ExecutorService и с чем его едят. Поэтому пришлось садиться за Eclipse, курить читать javadoc и разбираться.
Итак, давайте рассмотрим простой пример:
В данном примере мы создали сам обьект ExecutorService и вызвали на нём метод execute. Передав в него самую обычную имплементацию потока. Всё это можно было бы соорудить и старым дедовским способом, но так, согласитесь, гораздо проще и изящнее. Фактически, мы быстро ответвили от текущего потока другой, асинхронный, который может что-то там выполнить в фоне.
Сам объект ExecutorService мы создали с помощью фабрики. Её методы вполне очевидны, поэтому не будем особо мусолить. Вот некоторые из них:
Помимо метода execute, который вызывается по принципу «выстрелил и забыл», наш сервис ещё имеет метод submit. Отличие от первого лишь в том, что последний возвращает объект интерфейса Future. Это просто замечательная возможность контролировать состояние потока, который мы запустили в фоне. Делается примерно так:
Обратите внимание, что метод get насмерть блокирует текущий поток и будет ждать пока фоновый не завершится. Теперь не нужно всех этих неочевидных join-ов! Если же мы боимся что наш фоновый поток не завершится никогда, можем использовать get(long,TimeUnit).
Иногда приходится из фонового потока возвратить данные в текущий. В этом тоже нам поможет метод submit, но теперь нам нужно передать в него не Runnable, а Callable обьект. По сути это два одинаковых интерфейса, отличаются только тем, что последний может возвращать что-то:
Ну вот вкратце и всё. Остались методы создания ExecutorService-а в фабрике (их там много), остались методы самого ExecutorService, вопросы об обработке ошибок в фоновых потоках, но это уже совсем другая история…
На завершение не забывайте делать:
Или не делать, в случае, что все фоновые потоки у вас будут демонами.
Источник
Руководство по фоновой работе в Android. Часть 3: Executors и EventBus
Приветствую, коллеги. Рад видеть вас снова в третьей части «Руководства по фоновой работе в Android». Если не видели предыдущие части, вот они:
- Часть 1: AsyncTask
- Часть 2: Loaders
В прошлый раз мы разобрались, как работают Loaders, а сразу после этого Google взял и сообщил, что они полностью переписали LoaderManager. Видимо, мне надо позже вернуться к этой теме, но пока что буду следовать плану и делиться подробностями того, как организовать фоновую работу в Android исключительно с помощью джавовых thread pool executors, а также как EventBus может помочь в этом, и как всё это работает под капотом.
Давайте вспомним, в чём главная загвоздка: времязатратные операции вроде сетевых вызовов должны осуществляться в фоновом потоке, но публикация результата может происходить только в главном UI-потоке.
Также было бы здорово сохранять результат продолжительной операции при изменении конфигурации.
В предыдущих текстах мы разобрались, как делать это с помощью AsyncTasks и Loaders. Однако у этих API есть свои недостатки, из-за которых приходится реализовывать довольно сложные интерфейсы и абстрактные классы. Кроме того, они не позволяют нам писать модули с асинхронной работой на чистой Java из-за использования Android-специфичных API.
Из-за этих ограничений возник подход, опирающийся на executors. Давайте рассмотрим его. Для начала, понятно, нам надо разжиться потоками, куда мы сможем отправлять свои задачи для фоновой работы. Давайте создадим для этого класс Background:
Итак, у нас есть executor, и есть метод, позволяющий запустить какой-то код асинхронно, обернув его в Runnable или Callable.
Здорово, давайте попробуем засунуть результат операции в UI-поток. Не проблема, мы знаем, что нам требуется только Handler:
Но подождите, мы не знаем, существует ли в этот момент вообще наш UI, и если да, как он узнает, что надо что-то изменить?
Тут на помощь и приходит подход, называемый «шина событий» или event bus. Общая идея в том, что есть некая общая шина (или даже несколько), куда публикуются события. Кто угодно может в любое время начать слушать шину, получать события, а затем прекращать слушать (звучит похоже на RxJava, да? Дождитесь следующей статьи!)
В общем, нам нужны три составляющих:
Сама шина
Источник (или источники) событий
Слушатель (или слушатели) событий
Можно отразить эту структуру такой диаграммой:
Принципиальная схема передачи событий по шине
Шина событий
Никто не требует самостоятельно реализовывать шину с нуля. Можно выбрать одну из существующих реализаций: Google Guava, Otto или EventBus от greenrobot (у последнего есть стильная поддержка отправки событий на разные потоки с помощью аннотаций).
Объект шины мы можем использовать напрямую в наших презентерах, активностях, фрагментах и так далее, но я предпочитаю инкапсулировать его в том же классе Background:
Давайте напишем клиентский код, использующий конструкцию, которую мы соорудили. Предположим, что мы хотим инициализировать базу данных перед использованием приложения, и это, конечно, занимает время. Так что внутри приложения мы запускаем инициализацию в фоне и публикуем событие о том, что инициализация базы завершилась:
Так что, например, мы можем спрятать прогресс-бар и перейти к нашей MainActivity:
Проблема тут нам уже хорошо известна: нельзя модифицировать UI из фонового потока, а код выше пытается сделать именно это.
Так что нам надо либо воспользоваться возможностями работы с потоком из библиотеки greenrobot, либо сделать всё самим. Не стоит изобретать велосипед в продакшн-приложении, но в целях обучения давайте попробуем сделать это голыми руками, тем более, что это очень просто.
Но перед этим давайте немного закопаемся в сорцы и посмотрим, как вызывается метод, помеченный аннотацией Subscribe, когда событие публикуется.
Заглянем в исходный код шины событий Google Guava:
Как видим, шина событий хранит подписчиков в SubscriberRegistry и пытается передать каждое событие подписчику конкретно этого события (ключом здесь выступает название класса объекта). Список подписчиков можно представить себе в виде Map .
Обращение с потоками зависит от объекта dispatcher, который по умолчанию выставлен на Dispatcher.perThreadDispatchQueue().
Что же происходит внутри dispatcher:
Главное тут: PerThreadQueuedDispatcher использует ThreadLocal для хранения очереди событий. По сути, это означает, что метод подписчика будет вызван в том же самом потоке, в котором было опубликовано событие.
И что нам с этим делать? Решение нехитрое — просто публиковать события в том потоке, в котором хотите их обрабатывать:
Это работает, но привносит ту проблему, которую шина событий вроде как должна решать: понижение связности с помощью разделения публикации и обработки событий. С таким решением мы обязываем код, публикующий события, знать, в каком потоке клиент хотел бы обработать код.
Другим решением стало бы использование Handlers прямо в UI:
Это тоже не выглядит полноценным решением. И в этом состоит ограничение шины событий. Как с этим можно справиться? Конечно, с помощью RxJava! Но об этом — в следующей части.
От автора: Я вхожу в программный комитет конференции Mobius, и её программа на 90% готова. Скорее смотрите, что вам приготовила конференция, и ждите новостей о финализации программы!
Источник
Многопоточность в Java: ExecutorService
ExecutorService
До Java 5 для организации работы с несколькими потоками приходилось использовать сторонние имплеменации пулинга или писать свой. С появлением ExecutorService такая необходимость отпала.
ExecutorService исполняет асинхронный код в одном или нескольких потоках. Создание инстанса ExecutorService’а делается либо вручную через конкретные имплементации ( ScheduledThreadPoolExecutor или ThreadPoolExecutor ), но проще будет использовать фабрики класса Executors . Например, если надо создать пул с 2мя потоками, то делается это так:
ExecutorService service = Executors.newFixedThreadPool(2);
ExecutorService service = Executors.newCachedThreadPool();
ExecutorService service = Executors.newCachedThreadPool();
for ( int i = 0; i new Runnable() <
public void run() <
// snip. piece of code
>
>);
>
Метод submit также возвращает объект Future , который содержит информацию о статусе исполнения переданного Runnable или Callable (который может возвращать значение). Из него можно узнать выполнился ли переданный код успешно, или он еще выполняется. Вызов метода get на объекте Future возвратит значение, который возвращает Callable (или null , если используется Runnable ). Метод имеет 2 checked-исключения: InterruptedException , который бросается, когда выполнение прервано через метод interrupt() , или ExecutionException если код в Runnable или Callable бросил RuntimeException , что решает проблему поддержки исключений между потоками.
ScheduledExecutorService
Иногда требуется выполнение кода асихронно и периодически или требуется выполнить код через некоторое время, тогда на помощь приходит ScheduledExecutorService . Он позволяет поставить код выполняться в одном или нескольких потоках и сконфигурировать интервал или время, на которое выполненение будет отложено. Интервалом может быть время между двумя последовательными запусками или время между окончанием одного выполнения и началом другого. Методы ScheduledExecutorService возвращают ScheduledFuture , который также содержит значение отсрочки для выполнения ScheduledFuture .
Например, если требуется отложить выполнение на 5 секунд, потребуется следующий код:
Источник
Android Executor Tutorial and Examples
An Executor is an object that executes submitted Runnable tasks.
What is ExecutorService?
The Java ExecutorService is a construct that allows you to pass a task to be executed by a thread asynchronously. This service creates and maintains a reusable pool of threads for executing submitted tasks.
The service also manages a queue, which is used when there are more tasks than the number of threads in the pool and there is a need to queue up tasks until there is a free thread available to execute the task.
ThreadPoolExecutor
In this piece we want to look at ThreadPoolExecutor implementation of the ExecutorService with regards to Android Development.
To instantiate a ThreadpoolExecutor, You can either directly instantiate it using one of its constructor overloads, for example;
In the above we’ve instantiated 10 threads with a KeepAlive parameter of 0 milliseconds.
You can also instantiate it using one of the factory methods in the Executors class.
The above code has instantiated a ThreadPoolExecutor of 10 threads.
To instantiate a ThreadPoolExecutor of only one thread use the newSingleThreadExecutor() method:
To instantiate a ThreadPoolExecutor that adds threads as needed use the newCachedThreadPool() method:
When you instantiate your Executor Service, a few parameters are initialized. Depending on how you instantiated your Executor Service, you may manually specify these parameters or they may be provided for you by default. These parameters are:
corePool size – minimum number of threads that should be kept in the pool.
maxPool size – the maximum number of workers that can be in the pool.
workQueue – used to queue up tasks for the available worker threads.
keepAliveTime – If the current number of worker threads exceeds the core pool size and a keepAliveTime is set, then worker threads are shut down when there is no more work to do until the number of worker threads is back to the core pool size; a thread will wait for work for the keepAlive time, and when that is exceeded and no work arrives, it will shut down.
Quick Executor Examples
Let’s start by looking at some snippets of code before writing full examples later in the article, in both Java and Kotlin:
1. Using Executor with Handler
2. Example 2
3. Example 3
Let’s look at some full examples in Android.
Example 1: Android ThreadPoolExecutor simple Example
Here is a simple step by step example to teach you the threadpoolexecutor in android.
Step 1: Create Project
Start by creating an empty Android Studio project.
Step 2: Dependencies
No third party dependencies are needed for this example.
Step 3: Design Layout
Design a simple layout with buttons and textviews:
Step 5: Write Code
Go to MainActivity.java and start by adding imports, among them the following:
In our MainActivity define two instance fields:
The method below shows you how to create a Create a cacheable & infinite thread pool. If the length of the thread pool exceeds the processing needs, idle threads can be recycled flexibly. If there is no recycling, new threads can be created. The sample code is as follows:
The method below shows you how to create a fixed-length thread pool, which can control the maximum concurrent number of threads, and the excess threads will wait in the queue. The size of the fixed-length thread pool is best set according to system resources. Such as Runtime.getRuntime().availableProcessors()
Here is how we will shut down our ThreadPools:
The method below shows you how to create a single-threaded thread pool, it will only use a unique worker thread to perform tasks, ensuring that all tasks are executed in the specified order (FIFO, LIFO, priority). Single thread in Android can be used for database operations, file operations, application batch installation, application batch deletion, etc., which are not suitable for combined transmission but may be IO blocking and affect the UI thread response.
Here is the full code:
MainActivity.java
Copy the code or download it in the link below, build and run.
Reference
Here are the reference links:
Number | Link |
---|---|
1. | Download Example |
2. | Follow code author |
Example 2 – Android ThreadPoolExecutor
This is a simple example written in Java.
Step 1: Dependencies
No external dependencies are needed.
Step 2: Create MainActivity
Create your MainActivity as follows:
MainActivity.java
Step 4: Create Layout
Here is our MainActivity layout:
activity_main.xml
Reference
Example 3: Kotlin Android ThreadPoolExecutor Example
Let;s look at a ThreadPoolExecutor example in a step by step manner.
Step 1: Create Project
Start by creating an empty Android Studio project.
Step 2: Dependencies
No third party dependencies are needed.
Step 3: Create layout
We need to create a single layout and add some progressbars to it:
activity_executor.xml
Step 4: Write Code
We use the MVP Design Pattern. Start by creating a Contract:
Contract.kt
Then extend the Thread class to create our CounterThread :
CounterThread.kt
Then create our ExecutorPresentor :
ExecutorPresenter.kt
The finally the ExecutorActivity which is the launcher activity:
ExecutorActivity.kt
Copy the code or download it in the link below, build and run.
Reference
Here are the reference links:
Number | Link |
---|---|
1. | Download Example |
2. | Follow code author |
report this ad
Oclemy
Thanks for stopping by. My name is Oclemy(Clement Ochieng) and we have selected you as a recipient of a GIFT you may like ! Together with Skillshare we are offering you PROJECTS and 1000s of PREMIUM COURSES at Skillshare for FREE for 1 MONTH. To be eligible all you need is by sign up right now using my profile .
Источник