Многопоточная разработка для Android, часть 1

Многопоточность присутствует в Java изначально, все объекты в Java имеют встроенный механизм поточной синхронизации.

Один важный частный случай потоков в Java -Timer

Часто нужно выполнять какие-то действия через интервал времени. Можно сделать это при помощи потока и метода sleep(). Однако существует специализированная сущность, которая уже умеет все что нам нужно — это Timer(полное имя ). Timer умеет запускать ваши задания на выполнение, при этом задания представляют из себя потомков другого класса TimerTask (полное имя ). Эта пара классов представляет из себя специализацию для Thread и Runnable. Причем увидеть связь TimerTask и Runnable можно сразу, так как TimerTask реализует Runnable. Связь Timer и Thread менее очевидна.

Итак, как это работает. Сначала нужно определить потомка дляTimerTask, который будет выполнять периодическое задание, например писать в лог слово Hello.

class HelloTask extends TimerTask { public static final String TAG = (); /** * Ничего нового, тот же интерфейс Runnable. (не пишите такие * комментарии в реальном коде, ну пожалуйста) */ @Override public void run() { (); Log.i(TAG, “Hello”); } }

Теперь нужно создать таймер.

Timer t = new Timer();

И запустить задачу на выполнение, однако тут уже появляются варианты:

        • (new HelloTask(), new Date()) — даёт нам запуск нашего задания прямо сейчас, так как я использовал просто ‘new Date()’, можно определить, что-то по конкретней, Но суть вызова — можно назначить момент единственного исполнения.
        • (new HelloTask(), new Date(), 1000) — от сего момента, и каждую секунду(1000 миллисекунд). Сей момент можно определить любой. Тут важно понимать, что 1000 миллисекунд будет между удачными заверениями заданий, то есть если задание “опоздало”, например из-за вызова GC, то следующее тоже сдвинется по времени. У этого метода есть напарник, который вызывает задания именно через фиксированное время, не глядя на то, завершилось предыдущее или нет — это (new HelloTask(), new Date(), 1000).
        • (new HelloTask(), 60 * 1000) — как первый, но задается задержка в миллисекундах, в нашем случае — минута.
        • (new HelloTask(), 60 * 1000, 1000) — похож на второй метод, но смещение для перовго вызова задания задается в миллисекундах а не типом Date. Аналогично предыдущему периодическому таймеру имеет напарника, который вызывает именно через интервалы от начала, а не от конца выполнения метода — это scheduleAtFixedRate, сигнатура аналогичная базовому методу.
Читайте также:  Быстро садится батарея на Андроиде, что делать?

Чтобы остановить таймер нужно вызвать cancel(), вызвать его можно один раз, посе этого таймер больше не работает.

Не стоит разводить много таймеров в одной программе, чаще всего это приводит к труднообнаружимым ошибкам. Мы вас предупредили!

В завершение скажу, что пользоваться многопоточностью и особенно синхронизацией нужно аккуратно, так как можно получить взаимное блокирование потоков. Чаще всего взаимное блокирование имеет корни в архитектуре приложения, а значит исправить его будет не просто, поэтому нужно писать сразу правильно и не пытаться синхронизировать слишком много разных участков кода без особой нужды. Обычно более 2 семафоров в одном классе — признак того, что что-то идет не так.

Всем удачи, продолжение следует…

Материал предоставлен компанией Softeq Development, FLLC

Что такое Back-pressure в Reactive Streams

Как уже говорилось, мы возвращаем не объект, а “обещание” объекта – Publisher, который будет отдавать объекты, как только они появятся. Но кому? Subscriber-у – тому, кто подписывается на Publisher; подписчик может быть как один, так или много. Subscriber и получает объекты. Причем подписчик может регулировать скорость потока, это и называется Back-pressure (обратное давление).

Эта концепция была придумана для того, чтобы система имела возможность отказаться от получения того, что не способна обработать прямо сейчас, ведь часто речь идет о Big Data, и если скорость потока слишком велика, возникнет ошибка out-of-memory (иначе говоря, памяти не хватит). Система запрашивает столько элементов, сколько может обработать (при этом push-принцип остается, request просто обозначает возможный в данный момент максимум).

Что такое Back-pressure в Reactive Streams

На видео 11:14 все показано в динамике, но на картинке пока запрос первого элемента

Утечка памяти

А это самый неприятный недостаток AsyncTask, который напрямую следует из предыдущего пункта. После запуска нового Activity прошлый экземпляр UI должен быть выгружен из памяти сборщиком мусора. Но этого не произойдет, поскольку на «старый» UI есть ссылка в работающем потоке, созданном AsyncTask. Ничего не поделать, придется создавать еще один поток и запускать все вычисления в нем по новой. Но есть риск, что пользователь опять повернет экран! При такой организации рабочего процесса вся выделенная память потратится на содержание ненужных Activity и дополнительных потоков, и ОС принудительно завершит приложение с ошибкой OutOfMemoryException.

Читайте также:  Как запускать приложения для Android в Chrome на Mac / Linux / Windows

Что же делать?

Сделать экземпляр AsyncTask статическим и использовать слабые связи (WeakReference). При таком подходе в приложении не будут генериться лишние потоки, а слабая связность позволит сборщику мусора выгрузить ненужные Activity из памяти.

Какое из следующих утверждений верно?

  • в Java можно использовать множественное наследование реализаций
  • ничего из перечислен

Похожие ответы, выполненные работы

  • Задание по мировой экономике, КрасГАУ
  • C#_ ООП и классы
  • C#_ основы
  • Помощь с курсовой работой по информатике для ТулГУ,…
  • Создание Windows-приложений на основе Visual C#
  • Язык программирования C++ для профессионалов
  • Язык программирования C++
  • Основы программирования на C#
  • Помощь с тестом по дисциплине «Английский язык», ЮУрГУ
  • Программирование на языке C++