Страницы

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

суббота, 7 декабря 2019 г.

Обнуляются ли static поля после уничтожения всех экземпляров класса?

#java #android


Есть задача: запускать поток(Thread1) 1 раз и только. При этом, другой поток(Thread2)
периодически создает нужный поток(Thread1). Из за невозможности контролировать количество,
происходит повторение действий. Как решить красиво и правильно я не знаю.

Главный вопрос. Имеем 

 static Thread myThread;

            @Override
            public void run() {
                if (myThread != null) {
                    if (isAlive()) {
                        // Если поток есть, и живой, то return.
                        // Т.е. получается поток создался, 
                        // но не делая ничего завершился, 
                        // а предыдущий, который еще работает.... дорабатывает.
                        return;
                    }
                }
            // Если не было return, то поток работает
            }


Но, я переживаю что произойдет следующее: в потоке код выполняется в while(true)
{}, т.е. постоянно. На android. И если из за нехватки памяти или другим причинам ОС
она прибьет мой поток(Thread1), то другой поток(Thread2) создает его заново. Происходит
код выше, и если static Thread myThread не обнулится, то получится что и не работает
нужный поток и другие не смогут начать работу. Метода onDestroy нет не у Thread, не
у Runnable интерфейса.

Возможно я предложил очень "некрасивое" решение и делается это совсем не так, если
кто знает, подскажите в каком направлении смотреть. Я не совсем понимаю природу работы
сборщика мусора в java, и политики работы ОС Android(причины завершить процесс аварийно
и т.д.).

P.S. Вопрос вкратце: должен жить 1 поток либо ни одного. Если ни одного нет, иметь
возможность запустить 1.

UDP: Такой код вроде работает, не знаю как будет вести себя в нестандартных ситуациях.

public static Thread myThread;

     @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if (myThread == null) {
                myThread = new Thread(new TaskExecutor(this));
                myThread.start();
            } else {
                if (!myThread.isAlive()) {
                    myThread = new Thread(new TaskExecutor(this));
                    myThread.start();
                }
            }
            return START_STICKY;
        }


Первый вариант что я писал, там почему то не срабатывает this.isAlive() внутри потока
уже. Возвращает false; 

UPD 2: 
Eugene Krivenja ответ хороший. Но Создавая поток при пересоздании сервиса получается
так: Старый сервис создан, создал поток. Потом Сервис умирает (я его сам прибил), но
поток функционирует. Сервис пере создается, создает поток - имеем 2 рабочих потока,
которые дублируют действия. Статик переменная решила мою проблему, но как ты сказал
могут быть необъяснимые действия. Буду думать дальше, как сделать 100% безопасно.
    


Ответы

Ответ 1



Хранить что-либо в статических переменных на Андроид очень не рекомендуется. Могут происходить труднообьяснимые вещи. Все из-за механизма выгрузки-загрузки классов. Стандартный подход в вашем случае, создать потомка от класса Application и в нем хранить ссылку (не статическую) на поток, а сам поток создавать в onCreate(). В этом случае поток система уничтожит вместе с обьектом Application, а при перезапуске приложения Application создается самым первым, соответсвенно и поток будет создан. Второй вариант с сервисом рабочий, и наверное предпочтительный, только myThread опять же не должен быть статическим и поток уничтожится только вместе с сервисом. Поэтому не стоить перезапускать поток кем-то извне, надо перезапускать сам сервис. Как-то так. На Андроид кроме констант в статических переменных лучше ничего вообще не иметь.

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

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