You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
Repository navigation
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
BackgroundExecutor may cause deadlock for serial tasks #1689
First of all, this issue only happens when running robolectric test because I override the Executor, but it can happen in production if tasks are executed too fast.
I have the following executor, that simple execute tasks in serial for test purpose:
public class UIThreadExecutor implements Executor{
@Override
public void execute(@NonNull Runnable command) {
try {
command.run();
}catch (Exception ignored){
}
}
}
And I have the follow test:
@Test
public void testSerial(){
BackgroundExecutor.setExecutor(new UIThreadExecutor());
for (int i = 0; i < 10; i++){
activity.testSerial();
}
await().atMost(10, TimeUnit.SECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return activity.count == 10;
}
});
}
The activity testSerial implementation is:
public static int count = 0;
@Background(serial = "test")
public void testSerial(){
count++;
System.out.println("count = " + count);
}
If you run this test, it will cause dead lock. Digging in the code I was able find out why.
As you see the task is add after the directExecute is called. Let's take a look at the Task clean post executed code:
private void postExecute() {
if (id == null && serial == null) {
/* nothing to do */
return;
}
CURRENT_SERIAL.set(null);
synchronized (BackgroundExecutor.class) {
/* execution complete */
TASKS.remove(this);
if (serial != null) {
Task next = take(serial);
if (next != null) {
if (next.remainingDelay != 0) {
/* the delay may not have elapsed yet */
next.remainingDelay = Math.max(0L, targetTimeMillis - System.currentTimeMillis());
}
/* a task having the same serial was queued, execute it */
BackgroundExecutor.execute(next);
}
}
}
}
As you see in this code we remove the task after the execution, but my execution always finish before the Task is added to the stack. Causing a dead lock, because the task is added to to list and never removed.
One possible solution would be simple check if the task is already finished (managed) before add it to the list: if ( (task.id != null || task.serial != null) && !task.managed.get())
Activity
fix possible deadlock in serialized background androidannotations#1689
Revert "fix possible deadlock in serialized background androidannotat…
Support synchronous executors