MIDP системные потоки. Механизм работы и возможные проблемы

Использование параллельных потоков в рамках одного приложения является достаточно сложной темой. Хотя технология  Java и обеспечивает мощную поддержку мультипоточных приложений, встретить правильно написанный код все еще очень сложно. Чтобы помочь вам включиться в работу с потоками в J2SE 5.0 (называемой также Java 1.4) имеются полезные классы и утилиты. В их основу положена работа Дуга Ли (Doug Lea) - автора великолепной книги "Concurrent Programming in Java". К сожалению, эти новые классы все еще недоступны в J2ME, поэтому приходится довольствоваться приемами, изложенными в статье "Использование потоков в J2ME приложениях".  Темой данного документа являются системные потоки (system threads). Именно они, как правило, вызывают затруднения у начинающих программистов. Ниже рассмотрены проблемы, обусловленные спецификой системных потоков, и описаны пути их решения.

Системным называется любой поток, который не был порожден приложением и не контролируется им. В среде MIDP системные потоки создаются менеджером приложений (AMS - application management software) - программой контролирующий ход выполнения MIDlet-ов. Каждый активный мидлет помимо своих потоков имеет, по крайней мере, один системный.

Обратите внимание на слова "по крайней мере"! Приложение может использовать и большее количество системных потоков. При необходимости с ними могут совместно работать несколько мидлетов (если это не противоречит правилам "песочницы" [так называется одна из моделей безопасности, применяемая для мидлетов] или другим ограничениям.). MIDP не дает ни каких гарантий относительно того, какие потоки использует ASM для своих нужд.

Давайте задумаемся, как запускается наш мидлет? Судя по всему, для его загрузки и запуска AMS использует код, похожий на приведенный ниже.

// Load and start a MIDlet
String name= readMIDletName();
MIDlet m=null;
 
try{
m=(MIDlet)Class.forName( name).newInstance();
registerMIDlet( m);
}
catch( Throwable e){
abortMIDlet( name, m);
}



Этот код имеет слабое место: если мидлет зависнет в процессе работы его конструктора или запуска, будет блокирована и работа AMS. Более надежный AMS порождает для загрузки и запуска приложения новый поток.  Затем он некоторое время ожидает завершение инициализации мидлета, и если этого не происходит, завершает его работу. Таким образом, система остается в рабочем состоянии.

Сам по себе мидлет не имеет механизма контроля за процессом запуска, поэтому при разработке приложений старайтесь писать быстрый  и надежный метод startApp().

В большинстве случаев мидлеты зависают уже в ходе своего выполнения. AMS использует системные потоки для того, чтобы иметь возможность информировать мидлет о новых событиях(events) и посылать различные уведомления(notifications). (И опять нет никакой гарантии, что эти операции  будет выполнять один и тот же системный поток, хотя на практике чаще всего дело обстоит именно так.) Чтобы заставить мидлет реагировать на события и уведомления, AMS напрямую вызывает его методы. Например, когда по каким-то причинам AMS хочет обновить экран, он обращается к методу paint() объекта Canvas.

При обращении к методам мидлета AMS фактически теряет контроль над потоком. Чтобы гарантировать работоспособность системы, мидлет должен подчиняться двум простым правилам. Первое: методы обрабатывающие системные события или уведомления должны как можно быстрее завершать свою работу и возвращать управление AMS. Второе: запрещается блокировать системный поток, обратившийся к мидлету.

Быстрая обработка событий позволяет сохранять систему "бодрой" и чувствительной. Обычно к приложению обращается один поток событий(event thread), поскольку в большинстве случаев события имеют смысл, только когда они поставляются последовательно. При обработке долгой операции, состоящей из длинной цепочки событий, приложение может подвисать. Именно в таких ситуациях критическими оказываются скорости выполнения методов обработки событий.

Второе правило тоже порой бывает актуально. Так называемое блокирование происходит, когда поток приостанавливает свою работу и ждет результата выполнения другого потока. Это очень опасная практика, поскольку она легко может привести к зависанию всей системы. Чтобы не быть голословным, приведу пример.

 String url=...
Connection conn=null;
 
try{
conn= Connector.open( url);
// do something here
}
catch( IOException e){
// error
}

Здесь опасность кроется в природе метода open().  На некоторых платформах система выполняет соединение неявно в виде отдельного потока. Таким образом,  вызывающий метод open() поток блокируется до тех пор, пока коммуникационный поток не установит соединение. Однако система безопасности может потребовать подтверждения пользователя на установку соединения. Теперь уже коммуникационный поток блокируется, пока другой поток, обрабатывающий события (то есть наш первый поток) не получит подтверждение от пользователя. Но первый поток уже блокирован! Система зависает.

Для решения подобных проблем лучше всего переместить операции, которые могут вызвать блокировку в созданный приложением поток. Это конечно усложнит код мидлета, но сделает его более безопасным. Если вы хотите посмотреть, как это реализуется на практике, прочитайте статью "Выполнение HTTP соединения в виде потока".

Значительно облегчить жизнь могут различные интегрированные среды разработки. Например, J2ME Wireless Toolkit выдает сообщение, если в исходном коде кроется риск зависания. Помните об этой опасности при разработке многопоточных приложений. Во многих случаях многопоточные приложения более эффективны, но они требуют от программиста большего внимания и сноровки.

Автор:Eric Giguere, December 2004.
Перевод: Arix




Наши соцсети

Подписаться Facebook Подписаться Вконтакте Подписаться Twitter Подписаться Google Подписаться Telegram

Популярное

Ссылки

Новости [1] [2] [3]... Android/ iOS/ J2ME[1] [2] [3]) Android / Архив

Рейтинг@Mail.ru Яндекс.Метрика
MobiLab.ru © 2005-2018
При использовании материалов сайта ссылка на www.mobilab.ru обязательна