У меня есть исполняемый экземпляр, который снова самопланируется в конце своего метода run
:
private class MyRunnable implements Runnable {
private volatile boolean cancelled = false;
private Handler handler;
public MyRunnable(Handler h){
handler = h;
}
@Override
public void run(){
//Do stuff
if(!cancelled){
//Preemtion possible here?
handler.postDelayed(this, 1000);
}
}
public void selfStart(){
cancelled = false;
handler.removeCallbacks(this);
handler.post(this);
}
public void selfCancel(){
cancelled = true;
handler.removeCallbacks(this);
}
}
Выполняемый сначала планируется в основном потоке, вызывая selfStart
из onStart
действия.
В то же время runnable может быть отменен извне (вызовом selfCancel
) из действия onStop
, а также из широковещательного приемника.
Насколько я знаю, Runnable.run
, Activity.onStop
и BroadcastReceiver.onReceive
выполняются в одном и том же потоке (основном), поэтому на первый взгляд я подумал, что проблем с потокобезопасностью не будет.
Но иногда похоже, что исполняемый объект вытесняется в середине своего вызова run
, затем он отменяется из активности или получателя, а затем возобновляется и снова перепланируется.
Это возможно?
ОБНОВЛЕНИЕ:
Я постараюсь лучше объяснить проблему. Показанный выше класс предназначен для периодического запуска задач в основном потоке. В комментарии «делай что-нибудь» на самом деле есть код, который обновляет TextView
значением, переданным конструктору MyRunnable
. Активность отменяет текущий исполняемый объект и запускает новый при получении определенных намерений. Несмотря на то, что текущий runnable всегда запрашивается для отмены перед созданием нового, иногда он остается запущенным вместе с новым, поэтому в текстовом представлении отображаются чередующиеся значения. Это не предполагаемое поведение.
Я думал, что если runnable в данный момент выполняется в основном потоке, он будет работать до завершения, а затем другие runnables или обработчики событий будут извлечены из очереди и выполнены при необходимости, но ни одно ожидающее событие или runnable не может быть «выполнено наполовину» .
В основном потоке выполняются два вида задач, связанных с проблемой:
- R1: Самопланируемая задача
MyRunnable
. Запускается, а затем снова публикуется с задержкой в 1 с. - R2: обработчики событий, которые запрашивают отмену текущего экземпляра
MyRunnable
и создают новый R1'. Они происходят случайным образом и выполняются только один раз.
Я рассматривал два сценария. Первый:
- R1 уже работает в основном потоке.
- R2 прибывает и ставится в очередь в основном потоке.
- R1 завершает работу и снова публикует себя.
- R2 запускается и удаляет обратные вызовы для R1.
- R1 больше никогда не должен запускаться.
И второй:
- R1 не запущен, но запланирован.
- Приходит R2 и удаляет обратные вызовы для R1.
- R1 больше никогда не должен запускаться.
Теоретически, если приоритета нет и есть только один поток, почему иногда в основном потоке бывает два R1?