Страницы

Поиск по вопросам

понедельник, 8 октября 2018 г.

Выполнение параллельных потоков в AsyncTask

Пользуюсь AsyncTask для создания отдельного потока для постоянного вызова нативной функции. Все замечательно работало до тех пор, пока не понадобилось создать второй поток. Программа тупо зависает на execute() и ждет, пока первый поток завершится.
Чем лечить? Как создавать несколько потоков не блокирующих друг друга?


Ответ

До версии Android 1.6 при запуске задач AsyncTask использовалось только два потока:основной - UI и пользовательский - User. При этом если в пользовательском потоке запускалось более одной задачи, то остальные дожидались своей очереди на выполнение, пока все, что запущенны ранее не отработают свои задачи.То есть мы имели ни что иное, как двухзадачность. И увидели в Google, что это плохо.
с Android 1.6 ввели следующие изменения: Первые пять потоков запускались параллельно, а шестой и последующие дожидались, когда освободится какой то из первых пяти, но при этом, если очередь становилась более 10 потоков, то 16 и последующие вновь запускались параллельно (всего до 128), а те несчастливые с пятого до пятнадцатого так и ждали, когда освободится им место. Кроме того было отведено определенное время (10 секунд, а с Android 2.3 - 1 секунда)- если в течении этого времени появлялись еще новые потоки, то при завершении первых пяти они запускались вперед все тех же несчастных с пятого до пятнадцатого. Как видите в такой схеме разобраться очень не просто, она не очевидна и крайне запутана - программисты допускали множество ошибок и гугл засыпали жалобами.
С android 3.0 опять были введены изменения. В AsyncTask появился новый метод executeOnExecutor() , который имел два ключа:
AsyncTask.THREAD_POOL_EXECUTOR - параллельное выполнение потоков по страшной схеме, применяемой в Android 2.3 AsyncTask.SERIAL_EXECUTOR - последовательное выполнение потоков по схеме до android 1.6
метод execute() так же был оставлен для обратной совместимости, теперь он позволяет запустить последовательно 128 потоков. ( Работает по схеме применяемой до Android 1.6)
На сегодняшний день, если вы желаете, чтобы ваши потоки выполнялись параллельно, их следует запускать следующим образом (работает с API 11):
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Если минимальная версия вашего приложения меньше API 11 (Android 3.0), то вам придется придумывать какие то костыли, чтобы совместить желаемое поведение при запуске потоков, учитывая информацию выше, например:
public static void execute(AsyncTask as) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) { as.execute(); } else { as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }

Комментариев нет:

Отправить комментарий